parent
							
								
									96f44e1202
								
							
						
					
					
						commit
						d707738616
					
				| @ -1,4 +0,0 @@ | ||||
| #include "quantum.h" | ||||
| #include <avr/wdt.h> | ||||
| 
 | ||||
| void promicro_bootloader_jmp(bool program); | ||||
| @ -0,0 +1,159 @@ | ||||
| #include <util/twi.h> | ||||
| #include <avr/io.h> | ||||
| #include <stdlib.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <util/twi.h> | ||||
| #include <stdbool.h> | ||||
| #include "i2c.h" | ||||
| 
 | ||||
| // Limits the amount of we wait for any one i2c transaction.
 | ||||
| // Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
 | ||||
| // 9 bits, a single transaction will take around 90μs to complete.
 | ||||
| //
 | ||||
| // (F_CPU/SCL_CLOCK)  =>  # of μC cycles to transfer a bit
 | ||||
| // poll loop takes at least 8 clock cycles to execute
 | ||||
| #define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8 | ||||
| 
 | ||||
| #define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE) | ||||
| 
 | ||||
| volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; | ||||
| 
 | ||||
| static volatile uint8_t slave_buffer_pos; | ||||
| static volatile bool slave_has_register_set = false; | ||||
| 
 | ||||
| // Wait for an i2c operation to finish
 | ||||
| inline static | ||||
| void i2c_delay(void) { | ||||
|   uint16_t lim = 0; | ||||
|   while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT) | ||||
|     lim++; | ||||
| 
 | ||||
|   // easier way, but will wait slightly longer
 | ||||
|   // _delay_us(100);
 | ||||
| } | ||||
| 
 | ||||
| // Setup twi to run at 100kHz
 | ||||
| void i2c_master_init(void) { | ||||
|   // no prescaler
 | ||||
|   TWSR = 0; | ||||
|   // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
 | ||||
|   // Check datasheets for more info.
 | ||||
|   TWBR = ((F_CPU/SCL_CLOCK)-16)/2; | ||||
| } | ||||
| 
 | ||||
| // Start a transaction with the given i2c slave address. The direction of the
 | ||||
| // transfer is set with I2C_READ and I2C_WRITE.
 | ||||
| // returns: 0 => success
 | ||||
| //          1 => error
 | ||||
| uint8_t i2c_master_start(uint8_t address) { | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA); | ||||
| 
 | ||||
|   i2c_delay(); | ||||
| 
 | ||||
|   // check that we started successfully
 | ||||
|   if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START)) | ||||
|     return 1; | ||||
| 
 | ||||
|   TWDR = address; | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN); | ||||
| 
 | ||||
|   i2c_delay(); | ||||
| 
 | ||||
|   if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) | ||||
|     return 1; // slave did not acknowledge
 | ||||
|   else | ||||
|     return 0; // success
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Finish the i2c transaction.
 | ||||
| void i2c_master_stop(void) { | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | ||||
| 
 | ||||
|   uint16_t lim = 0; | ||||
|   while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT) | ||||
|     lim++; | ||||
| } | ||||
| 
 | ||||
| // Write one byte to the i2c slave.
 | ||||
| // returns 0 => slave ACK
 | ||||
| //         1 => slave NACK
 | ||||
| uint8_t i2c_master_write(uint8_t data) { | ||||
|   TWDR = data; | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN); | ||||
| 
 | ||||
|   i2c_delay(); | ||||
| 
 | ||||
|   // check if the slave acknowledged us
 | ||||
|   return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1; | ||||
| } | ||||
| 
 | ||||
| // Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
 | ||||
| // if ack=0 the acknowledge bit is not set.
 | ||||
| // returns: byte read from i2c device
 | ||||
| uint8_t i2c_master_read(int ack) { | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA); | ||||
| 
 | ||||
|   i2c_delay(); | ||||
|   return TWDR; | ||||
| } | ||||
| 
 | ||||
| void i2c_reset_state(void) { | ||||
|   TWCR = 0; | ||||
| } | ||||
| 
 | ||||
| void i2c_slave_init(uint8_t address) { | ||||
|   TWAR = address << 0; // slave i2c address
 | ||||
|   // TWEN  - twi enable
 | ||||
|   // TWEA  - enable address acknowledgement
 | ||||
|   // TWINT - twi interrupt flag
 | ||||
|   // TWIE  - enable the twi interrupt
 | ||||
|   TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN); | ||||
| } | ||||
| 
 | ||||
| ISR(TWI_vect); | ||||
| 
 | ||||
| ISR(TWI_vect) { | ||||
|   uint8_t ack = 1; | ||||
|   switch(TW_STATUS) { | ||||
|     case TW_SR_SLA_ACK: | ||||
|       // this device has been addressed as a slave receiver
 | ||||
|       slave_has_register_set = false; | ||||
|       break; | ||||
| 
 | ||||
|     case TW_SR_DATA_ACK: | ||||
|       // this device has received data as a slave receiver
 | ||||
|       // The first byte that we receive in this transaction sets the location
 | ||||
|       // of the read/write location of the slaves memory that it exposes over
 | ||||
|       // i2c.  After that, bytes will be written at slave_buffer_pos, incrementing
 | ||||
|       // slave_buffer_pos after each write.
 | ||||
|       if(!slave_has_register_set) { | ||||
|         slave_buffer_pos = TWDR; | ||||
|         // don't acknowledge the master if this memory loctaion is out of bounds
 | ||||
|         if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) { | ||||
|           ack = 0; | ||||
|           slave_buffer_pos = 0; | ||||
|         } | ||||
|         slave_has_register_set = true; | ||||
|       } else { | ||||
|         i2c_slave_buffer[slave_buffer_pos] = TWDR; | ||||
|         BUFFER_POS_INC(); | ||||
|       } | ||||
|       break; | ||||
| 
 | ||||
|     case TW_ST_SLA_ACK: | ||||
|     case TW_ST_DATA_ACK: | ||||
|       // master has addressed this device as a slave transmitter and is
 | ||||
|       // requesting data.
 | ||||
|       TWDR = i2c_slave_buffer[slave_buffer_pos]; | ||||
|       BUFFER_POS_INC(); | ||||
|       break; | ||||
| 
 | ||||
|     case TW_BUS_ERROR: // something went wrong, reset twi state
 | ||||
|       TWCR = 0; | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
|   // Reset everything, so we are ready for the next TWI interrupt
 | ||||
|   TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN); | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| #ifndef I2C_H | ||||
| #define I2C_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #ifndef F_CPU | ||||
| #define F_CPU 16000000UL | ||||
| #endif | ||||
| 
 | ||||
| #define I2C_READ 1 | ||||
| #define I2C_WRITE 0 | ||||
| 
 | ||||
| #define I2C_ACK 1 | ||||
| #define I2C_NACK 0 | ||||
| 
 | ||||
| #define SLAVE_BUFFER_SIZE 0x10 | ||||
| 
 | ||||
| // i2c SCL clock frequency
 | ||||
| #define SCL_CLOCK  100000L | ||||
| 
 | ||||
| extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; | ||||
| 
 | ||||
| void i2c_master_init(void); | ||||
| uint8_t i2c_master_start(uint8_t address); | ||||
| void i2c_master_stop(void); | ||||
| uint8_t i2c_master_write(uint8_t data); | ||||
| uint8_t i2c_master_read(int); | ||||
| void i2c_reset_state(void); | ||||
| void i2c_slave_init(uint8_t address); | ||||
| 
 | ||||
| #endif | ||||
| @ -0,0 +1,21 @@ | ||||
| #include "quantum.h" | ||||
| #include <avr/wdt.h> | ||||
| 
 | ||||
| void promicro_bootloader_jmp(bool program); | ||||
| 
 | ||||
| #define KEYMAP( \ | ||||
| 	k00, k01, k02, k03, k04, k05, k40, k41, k42, k43, k44, k45, \ | ||||
| 	k10, k11, k12, k13, k14, k15, k50, k51, k52, k53, k54, k55, \ | ||||
| 	k20, k21, k22, k23, k24, k25, k60, k61, k62, k63, k64, k65, \ | ||||
| 	k30, k31, k32, k33, k34, k35, k70, k71, k72, k73, k74, k75 \ | ||||
| 	) \ | ||||
| 	{ \ | ||||
| 		{ k00, k01, k02, k03, k04, k05 }, \ | ||||
| 		{ k10, k11, k12, k13, k14, k15 }, \ | ||||
| 		{ k20, k21, k22, k23, k24, k25 }, \ | ||||
| 		{ k30, k31, k32, k33, k34, k35 }, \ | ||||
| 		{ k40, k41, k42, k43, k44, k45 }, \ | ||||
| 		{ k50, k51, k52, k53, k54, k55 }, \ | ||||
| 		{ k60, k61, k62, k63, k64, k65 }, \ | ||||
| 		{ k70, k71, k72, k73, k74, k75 } \ | ||||
| 	} | ||||
| @ -0,0 +1,310 @@ | ||||
| /*
 | ||||
| Copyright 2012 Jun Wako <wakojun@gmail.com> | ||||
| 
 | ||||
| This program is free software: you can redistribute it and/or modify | ||||
| it under the terms of the GNU General Public License as published by | ||||
| the Free Software Foundation, either version 2 of the License, or | ||||
| (at your option) any later version. | ||||
| 
 | ||||
| This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| GNU General Public License for more details. | ||||
| 
 | ||||
| You should have received a copy of the GNU General Public License | ||||
| along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|  * scan matrix | ||||
|  */ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <avr/io.h> | ||||
| #include <avr/wdt.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <util/delay.h> | ||||
| #include "print.h" | ||||
| #include "debug.h" | ||||
| #include "util.h" | ||||
| #include "matrix.h" | ||||
| #include "i2c.h" | ||||
| #include "split_util.h" | ||||
| #include "pro_micro.h" | ||||
| #include "config.h" | ||||
| 
 | ||||
| #ifndef DEBOUNCE | ||||
| #   define DEBOUNCE	5 | ||||
| #endif | ||||
| 
 | ||||
| #define ERROR_DISCONNECT_COUNT 5 | ||||
| 
 | ||||
| static uint8_t debouncing = DEBOUNCE; | ||||
| static const int ROWS_PER_HAND = MATRIX_ROWS/2; | ||||
| static uint8_t error_count = 0; | ||||
| 
 | ||||
| static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; | ||||
| static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; | ||||
| 
 | ||||
| /* matrix state(1:on, 0:off) */ | ||||
| static matrix_row_t matrix[MATRIX_ROWS]; | ||||
| static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | ||||
| 
 | ||||
| static matrix_row_t read_cols(void); | ||||
| static void init_cols(void); | ||||
| static void unselect_rows(void); | ||||
| static void select_row(uint8_t row); | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_init_quantum(void) { | ||||
|     matrix_init_kb(); | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_scan_quantum(void) { | ||||
|     matrix_scan_kb(); | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_init_kb(void) { | ||||
|     matrix_init_user(); | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_scan_kb(void) { | ||||
|     matrix_scan_user(); | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_init_user(void) { | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void matrix_scan_user(void) { | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| uint8_t matrix_rows(void) | ||||
| { | ||||
|     return MATRIX_ROWS; | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| uint8_t matrix_cols(void) | ||||
| { | ||||
|     return MATRIX_COLS; | ||||
| } | ||||
| 
 | ||||
| void matrix_init(void) | ||||
| { | ||||
|     debug_enable = true; | ||||
|     debug_matrix = true; | ||||
|     debug_mouse = true; | ||||
|     // initialize row and col
 | ||||
|     unselect_rows(); | ||||
|     init_cols(); | ||||
| 
 | ||||
|     TX_RX_LED_INIT; | ||||
| 
 | ||||
|     // initialize matrix state: all keys off
 | ||||
|     for (uint8_t i=0; i < MATRIX_ROWS; i++) { | ||||
|         matrix[i] = 0; | ||||
|         matrix_debouncing[i] = 0; | ||||
|     } | ||||
| 
 | ||||
|     matrix_init_quantum(); | ||||
| } | ||||
| 
 | ||||
| uint8_t _matrix_scan(void) | ||||
| { | ||||
|     // Right hand is stored after the left in the matirx so, we need to offset it
 | ||||
|     int offset = isLeftHand ? 0 : (ROWS_PER_HAND); | ||||
| 
 | ||||
|     for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { | ||||
|         select_row(i); | ||||
|         _delay_us(30);  // without this wait read unstable value.
 | ||||
|         matrix_row_t cols = read_cols(); | ||||
|         if (matrix_debouncing[i+offset] != cols) { | ||||
|             matrix_debouncing[i+offset] = cols; | ||||
|             debouncing = DEBOUNCE; | ||||
|         } | ||||
|         unselect_rows(); | ||||
|     } | ||||
| 
 | ||||
|     if (debouncing) { | ||||
|         if (--debouncing) { | ||||
|             _delay_ms(1); | ||||
|         } else { | ||||
|             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { | ||||
|                 matrix[i+offset] = matrix_debouncing[i+offset]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| // Get rows from other half over i2c
 | ||||
| int i2c_transaction(void) { | ||||
|     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; | ||||
| 
 | ||||
|     int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); | ||||
|     if (err) goto i2c_error; | ||||
| 
 | ||||
|     // start of matrix stored at 0x00
 | ||||
|     err = i2c_master_write(0x00); | ||||
|     if (err) goto i2c_error; | ||||
| 
 | ||||
|     // Start read
 | ||||
|     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); | ||||
|     if (err) goto i2c_error; | ||||
| 
 | ||||
|     if (!err) { | ||||
|         int i; | ||||
|         for (i = 0; i < ROWS_PER_HAND-1; ++i) { | ||||
|             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); | ||||
|         } | ||||
|         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK); | ||||
|         i2c_master_stop(); | ||||
|     } else { | ||||
| i2c_error: // the cable is disconnceted, or something else went wrong
 | ||||
|         i2c_reset_state(); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #ifndef USE_I2C | ||||
| int serial_transaction(void) { | ||||
|     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; | ||||
| 
 | ||||
|     if (serial_update_buffers()) { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||||
|         matrix[slaveOffset+i] = serial_slave_buffer[i]; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| uint8_t matrix_scan(void) | ||||
| { | ||||
|     int ret = _matrix_scan(); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #ifdef USE_I2C | ||||
|     if( i2c_transaction() ) { | ||||
| #else | ||||
|     if( serial_transaction() ) { | ||||
| #endif | ||||
|         // turn on the indicator led when halves are disconnected
 | ||||
|         TXLED1; | ||||
| 
 | ||||
|         error_count++; | ||||
| 
 | ||||
|         if (error_count > ERROR_DISCONNECT_COUNT) { | ||||
|             // reset other half if disconnected
 | ||||
|             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; | ||||
|             for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||||
|                 matrix[slaveOffset+i] = 0; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         // turn off the indicator led on no error
 | ||||
|         TXLED0; | ||||
|         error_count = 0; | ||||
|     } | ||||
| 
 | ||||
|     matrix_scan_quantum(); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void matrix_slave_scan(void) { | ||||
|     _matrix_scan(); | ||||
| 
 | ||||
|     int offset = (isLeftHand) ? 0 : (MATRIX_ROWS / 2); | ||||
| 
 | ||||
| #ifdef USE_I2C | ||||
|     for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||||
|         /* i2c_slave_buffer[i] = matrix[offset+i]; */ | ||||
|         i2c_slave_buffer[i] = matrix[offset+i]; | ||||
|     } | ||||
| #else | ||||
|     for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||||
|         serial_slave_buffer[i] = matrix[offset+i]; | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| bool matrix_is_modified(void) | ||||
| { | ||||
|     if (debouncing) return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| bool matrix_is_on(uint8_t row, uint8_t col) | ||||
| { | ||||
|     return (matrix[row] & ((matrix_row_t)1<<col)); | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| matrix_row_t matrix_get_row(uint8_t row) | ||||
| { | ||||
|     return matrix[row]; | ||||
| } | ||||
| 
 | ||||
| void matrix_print(void) | ||||
| { | ||||
|     print("\nr/c 0123456789ABCDEF\n"); | ||||
|     for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | ||||
|         phex(row); print(": "); | ||||
|         pbin_reverse16(matrix_get_row(row)); | ||||
|         print("\n"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t matrix_key_count(void) | ||||
| { | ||||
|     uint8_t count = 0; | ||||
|     for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||||
|         count += bitpop16(matrix[i]); | ||||
|     } | ||||
|     return count; | ||||
| } | ||||
| 
 | ||||
| static void  init_cols(void) | ||||
| { | ||||
|     for(int x = 0; x < MATRIX_COLS; x++) { | ||||
|         _SFR_IO8((col_pins[x] >> 4) + 1) &=  ~_BV(col_pins[x] & 0xF); | ||||
|         _SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static matrix_row_t read_cols(void) | ||||
| { | ||||
|     matrix_row_t result = 0; | ||||
|     for(int x = 0; x < MATRIX_COLS; x++) {      | ||||
|         result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x); | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| static void unselect_rows(void) | ||||
| { | ||||
|     for(int x = 0; x < ROWS_PER_HAND; x++) {  | ||||
|         _SFR_IO8((row_pins[x] >> 4) + 1) &=  ~_BV(row_pins[x] & 0xF); | ||||
|         _SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void select_row(uint8_t row) | ||||
| { | ||||
|     _SFR_IO8((row_pins[row] >> 4) + 1) |=  _BV(row_pins[row] & 0xF); | ||||
|     _SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF); | ||||
| } | ||||
| @ -0,0 +1,362 @@ | ||||
| /*
 | ||||
|   pins_arduino.h - Pin definition functions for Arduino | ||||
|   Part of Arduino - http://www.arduino.cc/
 | ||||
| 
 | ||||
|   Copyright (c) 2007 David A. Mellis | ||||
| 
 | ||||
|   This library is free software; you can redistribute it and/or | ||||
|   modify it under the terms of the GNU Lesser General Public | ||||
|   License as published by the Free Software Foundation; either | ||||
|   version 2.1 of the License, or (at your option) any later version. | ||||
| 
 | ||||
|   This library is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|   Lesser General Public License for more details. | ||||
| 
 | ||||
|   You should have received a copy of the GNU Lesser General | ||||
|   Public License along with this library; if not, write to the | ||||
|   Free Software Foundation, Inc., 59 Temple Place, Suite 330, | ||||
|   Boston, MA  02111-1307  USA | ||||
| 
 | ||||
|   $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ | ||||
| */ | ||||
| 
 | ||||
| #ifndef Pins_Arduino_h | ||||
| #define Pins_Arduino_h | ||||
| 
 | ||||
| #include <avr/pgmspace.h> | ||||
| 
 | ||||
| // Workaround for wrong definitions in "iom32u4.h".
 | ||||
| // This should be fixed in the AVR toolchain.
 | ||||
| #undef UHCON | ||||
| #undef UHINT | ||||
| #undef UHIEN | ||||
| #undef UHADDR | ||||
| #undef UHFNUM | ||||
| #undef UHFNUML | ||||
| #undef UHFNUMH | ||||
| #undef UHFLEN | ||||
| #undef UPINRQX | ||||
| #undef UPINTX | ||||
| #undef UPNUM | ||||
| #undef UPRST | ||||
| #undef UPCONX | ||||
| #undef UPCFG0X | ||||
| #undef UPCFG1X | ||||
| #undef UPSTAX | ||||
| #undef UPCFG2X | ||||
| #undef UPIENX | ||||
| #undef UPDATX | ||||
| #undef TCCR2A | ||||
| #undef WGM20 | ||||
| #undef WGM21 | ||||
| #undef COM2B0 | ||||
| #undef COM2B1 | ||||
| #undef COM2A0 | ||||
| #undef COM2A1 | ||||
| #undef TCCR2B | ||||
| #undef CS20 | ||||
| #undef CS21 | ||||
| #undef CS22 | ||||
| #undef WGM22 | ||||
| #undef FOC2B | ||||
| #undef FOC2A | ||||
| #undef TCNT2 | ||||
| #undef TCNT2_0 | ||||
| #undef TCNT2_1 | ||||
| #undef TCNT2_2 | ||||
| #undef TCNT2_3 | ||||
| #undef TCNT2_4 | ||||
| #undef TCNT2_5 | ||||
| #undef TCNT2_6 | ||||
| #undef TCNT2_7 | ||||
| #undef OCR2A | ||||
| #undef OCR2_0 | ||||
| #undef OCR2_1 | ||||
| #undef OCR2_2 | ||||
| #undef OCR2_3 | ||||
| #undef OCR2_4 | ||||
| #undef OCR2_5 | ||||
| #undef OCR2_6 | ||||
| #undef OCR2_7 | ||||
| #undef OCR2B | ||||
| #undef OCR2_0 | ||||
| #undef OCR2_1 | ||||
| #undef OCR2_2 | ||||
| #undef OCR2_3 | ||||
| #undef OCR2_4 | ||||
| #undef OCR2_5 | ||||
| #undef OCR2_6 | ||||
| #undef OCR2_7 | ||||
| 
 | ||||
| #define NUM_DIGITAL_PINS  30 | ||||
| #define NUM_ANALOG_INPUTS 12 | ||||
| 
 | ||||
| #define TX_RX_LED_INIT  DDRD |= (1<<5), DDRB |= (1<<0) | ||||
| #define TXLED0          PORTD |= (1<<5) | ||||
| #define TXLED1          PORTD &= ~(1<<5) | ||||
| #define RXLED0          PORTB |= (1<<0) | ||||
| #define RXLED1          PORTB &= ~(1<<0) | ||||
| 
 | ||||
| static const uint8_t SDA = 2; | ||||
| static const uint8_t SCL = 3; | ||||
| #define LED_BUILTIN 13 | ||||
| 
 | ||||
| // Map SPI port to 'new' pins D14..D17
 | ||||
| static const uint8_t SS   = 17; | ||||
| static const uint8_t MOSI = 16; | ||||
| static const uint8_t MISO = 14; | ||||
| static const uint8_t SCK  = 15; | ||||
| 
 | ||||
| // Mapping of analog pins as digital I/O
 | ||||
| // A6-A11 share with digital pins
 | ||||
| static const uint8_t A0 = 18; | ||||
| static const uint8_t A1 = 19; | ||||
| static const uint8_t A2 = 20; | ||||
| static const uint8_t A3 = 21; | ||||
| static const uint8_t A4 = 22; | ||||
| static const uint8_t A5 = 23; | ||||
| static const uint8_t A6 = 24;   // D4
 | ||||
| static const uint8_t A7 = 25;   // D6
 | ||||
| static const uint8_t A8 = 26;   // D8
 | ||||
| static const uint8_t A9 = 27;   // D9
 | ||||
| static const uint8_t A10 = 28;  // D10
 | ||||
| static const uint8_t A11 = 29;  // D12
 | ||||
| 
 | ||||
| #define digitalPinToPCICR(p)    ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCICR) : ((uint8_t *)0)) | ||||
| #define digitalPinToPCICRbit(p) 0 | ||||
| #define digitalPinToPCMSK(p)    ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCMSK0) : ((uint8_t *)0)) | ||||
| #define digitalPinToPCMSKbit(p) ( ((p) >= 8 && (p) <= 11) ? (p) - 4 : ((p) == 14 ? 3 : ((p) == 15 ? 1 : ((p) == 16 ? 2 : ((p) == 17 ? 0 : (p - A8 + 4)))))) | ||||
| 
 | ||||
| //  __AVR_ATmega32U4__ has an unusual mapping of pins to channels
 | ||||
| extern const uint8_t PROGMEM analog_pin_to_channel_PGM[]; | ||||
| #define analogPinToChannel(P)  ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) ) | ||||
| 
 | ||||
| #define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT))))) | ||||
| 
 | ||||
| #ifdef ARDUINO_MAIN | ||||
| 
 | ||||
| // On the Arduino board, digital pins are also used
 | ||||
| // for the analog output (software PWM).  Analog input
 | ||||
| // pins are a separate set.
 | ||||
| 
 | ||||
| // ATMEL ATMEGA32U4 / ARDUINO LEONARDO
 | ||||
| //
 | ||||
| // D0               PD2                 RXD1/INT2
 | ||||
| // D1               PD3                 TXD1/INT3
 | ||||
| // D2               PD1     SDA         SDA/INT1
 | ||||
| // D3#              PD0     PWM8/SCL    OC0B/SCL/INT0
 | ||||
| // D4       A6      PD4                 ADC8
 | ||||
| // D5#              PC6     ???         OC3A/#OC4A
 | ||||
| // D6#      A7      PD7     FastPWM     #OC4D/ADC10
 | ||||
| // D7               PE6                 INT6/AIN0
 | ||||
| //
 | ||||
| // D8       A8      PB4                 ADC11/PCINT4
 | ||||
| // D9#      A9      PB5     PWM16       OC1A/#OC4B/ADC12/PCINT5
 | ||||
| // D10#     A10     PB6     PWM16       OC1B/0c4B/ADC13/PCINT6
 | ||||
| // D11#             PB7     PWM8/16     0C0A/OC1C/#RTS/PCINT7
 | ||||
| // D12      A11     PD6                 T1/#OC4D/ADC9
 | ||||
| // D13#             PC7     PWM10       CLK0/OC4A
 | ||||
| //
 | ||||
| // A0       D18     PF7                 ADC7
 | ||||
| // A1       D19     PF6                 ADC6
 | ||||
| // A2       D20     PF5                 ADC5
 | ||||
| // A3       D21     PF4                 ADC4
 | ||||
| // A4       D22     PF1                 ADC1
 | ||||
| // A5       D23     PF0                 ADC0
 | ||||
| //
 | ||||
| // New pins D14..D17 to map SPI port to digital pins
 | ||||
| //
 | ||||
| // MISO     D14     PB3                 MISO,PCINT3
 | ||||
| // SCK      D15     PB1                 SCK,PCINT1
 | ||||
| // MOSI     D16     PB2                 MOSI,PCINT2
 | ||||
| // SS       D17     PB0                 RXLED,SS/PCINT0
 | ||||
| //
 | ||||
| // Connected LEDs on board for TX and RX
 | ||||
| // TXLED    D24     PD5                 XCK1
 | ||||
| // RXLED    D17     PB0
 | ||||
| // HWB              PE2                 HWB
 | ||||
| 
 | ||||
| // these arrays map port names (e.g. port B) to the
 | ||||
| // appropriate addresses for various functions (e.g. reading
 | ||||
| // and writing)
 | ||||
| const uint16_t PROGMEM port_to_mode_PGM[] = { | ||||
|     NOT_A_PORT, | ||||
|     NOT_A_PORT, | ||||
|     (uint16_t) &DDRB, | ||||
|     (uint16_t) &DDRC, | ||||
|     (uint16_t) &DDRD, | ||||
|     (uint16_t) &DDRE, | ||||
|     (uint16_t) &DDRF, | ||||
| }; | ||||
| 
 | ||||
| const uint16_t PROGMEM port_to_output_PGM[] = { | ||||
|     NOT_A_PORT, | ||||
|     NOT_A_PORT, | ||||
|     (uint16_t) &PORTB, | ||||
|     (uint16_t) &PORTC, | ||||
|     (uint16_t) &PORTD, | ||||
|     (uint16_t) &PORTE, | ||||
|     (uint16_t) &PORTF, | ||||
| }; | ||||
| 
 | ||||
| const uint16_t PROGMEM port_to_input_PGM[] = { | ||||
|     NOT_A_PORT, | ||||
|     NOT_A_PORT, | ||||
|     (uint16_t) &PINB, | ||||
|     (uint16_t) &PINC, | ||||
|     (uint16_t) &PIND, | ||||
|     (uint16_t) &PINE, | ||||
|     (uint16_t) &PINF, | ||||
| }; | ||||
| 
 | ||||
| const uint8_t PROGMEM digital_pin_to_port_PGM[] = { | ||||
|     PD, // D0 - PD2
 | ||||
|     PD, // D1 - PD3
 | ||||
|     PD, // D2 - PD1
 | ||||
|     PD, // D3 - PD0
 | ||||
|     PD, // D4 - PD4
 | ||||
|     PC, // D5 - PC6
 | ||||
|     PD, // D6 - PD7
 | ||||
|     PE, // D7 - PE6
 | ||||
|      | ||||
|     PB, // D8 - PB4
 | ||||
|     PB, // D9 - PB5
 | ||||
|     PB, // D10 - PB6
 | ||||
|     PB, // D11 - PB7
 | ||||
|     PD, // D12 - PD6
 | ||||
|     PC, // D13 - PC7
 | ||||
|      | ||||
|     PB, // D14 - MISO - PB3
 | ||||
|     PB, // D15 - SCK - PB1
 | ||||
|     PB, // D16 - MOSI - PB2
 | ||||
|     PB, // D17 - SS - PB0
 | ||||
|      | ||||
|     PF, // D18 - A0 - PF7
 | ||||
|     PF, // D19 - A1 - PF6
 | ||||
|     PF, // D20 - A2 - PF5
 | ||||
|     PF, // D21 - A3 - PF4
 | ||||
|     PF, // D22 - A4 - PF1
 | ||||
|     PF, // D23 - A5 - PF0
 | ||||
|      | ||||
|     PD, // D24 - PD5
 | ||||
|     PD, // D25 / D6 - A7 - PD7
 | ||||
|     PB, // D26 / D8 - A8 - PB4
 | ||||
|     PB, // D27 / D9 - A9 - PB5
 | ||||
|     PB, // D28 / D10 - A10 - PB6
 | ||||
|     PD, // D29 / D12 - A11 - PD6
 | ||||
| }; | ||||
| 
 | ||||
| const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { | ||||
|     _BV(2), // D0 - PD2
 | ||||
|     _BV(3), // D1 - PD3
 | ||||
|     _BV(1), // D2 - PD1
 | ||||
|     _BV(0), // D3 - PD0
 | ||||
|     _BV(4), // D4 - PD4
 | ||||
|     _BV(6), // D5 - PC6
 | ||||
|     _BV(7), // D6 - PD7
 | ||||
|     _BV(6), // D7 - PE6
 | ||||
|      | ||||
|     _BV(4), // D8 - PB4
 | ||||
|     _BV(5), // D9 - PB5
 | ||||
|     _BV(6), // D10 - PB6
 | ||||
|     _BV(7), // D11 - PB7
 | ||||
|     _BV(6), // D12 - PD6
 | ||||
|     _BV(7), // D13 - PC7
 | ||||
|      | ||||
|     _BV(3), // D14 - MISO - PB3
 | ||||
|     _BV(1), // D15 - SCK - PB1
 | ||||
|     _BV(2), // D16 - MOSI - PB2
 | ||||
|     _BV(0), // D17 - SS - PB0
 | ||||
|      | ||||
|     _BV(7), // D18 - A0 - PF7
 | ||||
|     _BV(6), // D19 - A1 - PF6
 | ||||
|     _BV(5), // D20 - A2 - PF5
 | ||||
|     _BV(4), // D21 - A3 - PF4
 | ||||
|     _BV(1), // D22 - A4 - PF1
 | ||||
|     _BV(0), // D23 - A5 - PF0
 | ||||
|      | ||||
|     _BV(5), // D24 - PD5
 | ||||
|     _BV(7), // D25 / D6 - A7 - PD7
 | ||||
|     _BV(4), // D26 / D8 - A8 - PB4
 | ||||
|     _BV(5), // D27 / D9 - A9 - PB5
 | ||||
|     _BV(6), // D28 / D10 - A10 - PB6
 | ||||
|     _BV(6), // D29 / D12 - A11 - PD6
 | ||||
| }; | ||||
| 
 | ||||
| const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { | ||||
|     NOT_ON_TIMER,    | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     TIMER0B,        /* 3 */ | ||||
|     NOT_ON_TIMER, | ||||
|     TIMER3A,        /* 5 */ | ||||
|     TIMER4D,        /* 6 */ | ||||
|     NOT_ON_TIMER,    | ||||
|      | ||||
|     NOT_ON_TIMER,    | ||||
|     TIMER1A,        /* 9 */ | ||||
|     TIMER1B,        /* 10 */ | ||||
|     TIMER0A,        /* 11 */ | ||||
|      | ||||
|     NOT_ON_TIMER,    | ||||
|     TIMER4A,        /* 13 */ | ||||
|      | ||||
|     NOT_ON_TIMER,    | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
| 
 | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
|     NOT_ON_TIMER, | ||||
| }; | ||||
| 
 | ||||
| const uint8_t PROGMEM analog_pin_to_channel_PGM[] = { | ||||
|     7,  // A0               PF7                 ADC7
 | ||||
|     6,  // A1               PF6                 ADC6    
 | ||||
|     5,  // A2               PF5                 ADC5    
 | ||||
|     4,  // A3               PF4                 ADC4
 | ||||
|     1,  // A4               PF1                 ADC1    
 | ||||
|     0,  // A5               PF0                 ADC0    
 | ||||
|     8,  // A6       D4      PD4                 ADC8
 | ||||
|     10, // A7       D6      PD7                 ADC10
 | ||||
|     11, // A8       D8      PB4                 ADC11
 | ||||
|     12, // A9       D9      PB5                 ADC12
 | ||||
|     13, // A10      D10     PB6                 ADC13
 | ||||
|     9   // A11      D12     PD6                 ADC9
 | ||||
| }; | ||||
| 
 | ||||
| #endif /* ARDUINO_MAIN */ | ||||
| 
 | ||||
| // These serial port names are intended to allow libraries and architecture-neutral
 | ||||
| // sketches to automatically default to the correct port name for a particular type
 | ||||
| // of use.  For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
 | ||||
| // the first hardware serial port whose RX/TX pins are not dedicated to another use.
 | ||||
| //
 | ||||
| // SERIAL_PORT_MONITOR        Port which normally prints to the Arduino Serial Monitor
 | ||||
| //
 | ||||
| // SERIAL_PORT_USBVIRTUAL     Port which is USB virtual serial
 | ||||
| //
 | ||||
| // SERIAL_PORT_LINUXBRIDGE    Port which connects to a Linux system via Bridge library
 | ||||
| //
 | ||||
| // SERIAL_PORT_HARDWARE       Hardware serial port, physical RX & TX pins.
 | ||||
| //
 | ||||
| // SERIAL_PORT_HARDWARE_OPEN  Hardware serial ports which are open for use.  Their RX & TX
 | ||||
| //                            pins are NOT connected to anything by default.
 | ||||
| #define SERIAL_PORT_MONITOR        Serial | ||||
| #define SERIAL_PORT_USBVIRTUAL     Serial | ||||
| #define SERIAL_PORT_HARDWARE       Serial1 | ||||
| #define SERIAL_PORT_HARDWARE_OPEN  Serial1 | ||||
| 
 | ||||
| #endif /* Pins_Arduino_h */ | ||||
| @ -0,0 +1,67 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/wdt.h> | ||||
| #include <avr/power.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <util/delay.h> | ||||
| #include <avr/eeprom.h> | ||||
| #include "split_util.h" | ||||
| #include "matrix.h" | ||||
| #include "i2c.h" | ||||
| #include "keyboard.h" | ||||
| #include "config.h" | ||||
| 
 | ||||
| volatile bool isLeftHand = true; | ||||
| 
 | ||||
| static void setup_handedness(void) { | ||||
|     isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); | ||||
| } | ||||
| 
 | ||||
| static void keyboard_master_setup(void) { | ||||
| #ifdef USE_I2C | ||||
|     i2c_master_init(); | ||||
| #else | ||||
|     serial_master_init(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void keyboard_slave_setup(void) { | ||||
| #ifdef USE_I2C | ||||
|     i2c_slave_init(SLAVE_I2C_ADDRESS); | ||||
| #else | ||||
|     serial_slave_init(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| bool has_usb(void) { | ||||
|    USBCON |= (1 << OTGPADE); //enables VBUS pad
 | ||||
|    _delay_us(5); | ||||
|    return (USBSTA & (1<<VBUS));  //checks state of VBUS
 | ||||
| } | ||||
| 
 | ||||
| void split_keyboard_setup(void) { | ||||
|    setup_handedness(); | ||||
| 
 | ||||
|    if (has_usb()) { | ||||
|       keyboard_master_setup(); | ||||
|    } else { | ||||
|       keyboard_slave_setup(); | ||||
|    } | ||||
|    sei(); | ||||
| } | ||||
| 
 | ||||
| void keyboard_slave_loop(void) { | ||||
|    matrix_init(); | ||||
| 
 | ||||
|    while (1) { | ||||
|       matrix_slave_scan(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| // this code runs before the usb and keyboard is initialized
 | ||||
| void matrix_setup(void) { | ||||
|     split_keyboard_setup(); | ||||
| 
 | ||||
|     if (!has_usb()) { | ||||
|         keyboard_slave_loop(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| #ifndef SPLIT_KEYBOARD_UTIL_H | ||||
| #define SPLIT_KEYBOARD_UTIL_H | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define EECONFIG_BOOTMAGIC_END      (uint8_t *)10 | ||||
| #define EECONFIG_HANDEDNESS         EECONFIG_BOOTMAGIC_END | ||||
| 
 | ||||
| #define SLAVE_I2C_ADDRESS           0x32 | ||||
| 
 | ||||
| extern volatile bool isLeftHand; | ||||
| 
 | ||||
| // slave version of matix scan, defined in matrix.c
 | ||||
| void matrix_slave_scan(void); | ||||
| 
 | ||||
| void split_keyboard_setup(void); | ||||
| bool has_usb(void); | ||||
| void keyboard_slave_loop(void); | ||||
| 
 | ||||
| #endif | ||||
| @ -0,0 +1,226 @@ | ||||
| # Hey Emacs, this is a -*- makefile -*-
 | ||||
| 
 | ||||
| # AVR-GCC Makefile template, derived from the WinAVR template (which
 | ||||
| # is public domain), believed to be neutral to any flavor of "make"
 | ||||
| # (GNU make, BSD make, SysV make)
 | ||||
| 
 | ||||
| 
 | ||||
| MCU = atmega328p | ||||
| FORMAT = ihex | ||||
| TARGET = keyboard-i2c-slave | ||||
| SRC = \
 | ||||
| 	$(TARGET).c \
 | ||||
| 	uno-matrix.c \
 | ||||
| 	../serial.c \
 | ||||
| 	../i2c-slave.c | ||||
| 
 | ||||
| ASRC = | ||||
| OPT = s | ||||
| 
 | ||||
| # Programming support using avrdude. Settings and variables.
 | ||||
| 
 | ||||
| AVRDUDE_PROGRAMMER = arduino | ||||
| AVRDUDE_PORT = /dev/ttyACM0 | ||||
| 
 | ||||
| # Name of this Makefile (used for "make depend").
 | ||||
| MAKEFILE = Makefile | ||||
| 
 | ||||
| # Debugging format.
 | ||||
| # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
 | ||||
| # AVR (extended) COFF requires stabs, plus an avr-objcopy run.
 | ||||
| DEBUG = stabs | ||||
| 
 | ||||
| # Compiler flag to set the C Standard level.
 | ||||
| # c89   - "ANSI" C
 | ||||
| # gnu89 - c89 plus GCC extensions
 | ||||
| # c99   - ISO C99 standard (not yet fully implemented)
 | ||||
| # gnu99 - c99 plus GCC extensions
 | ||||
| CSTANDARD = -std=gnu99 | ||||
| 
 | ||||
| # Place -D or -U options here
 | ||||
| CDEFS = | ||||
| 
 | ||||
| # Place -I options here
 | ||||
| CINCS = | ||||
| 
 | ||||
| 
 | ||||
| CDEBUG = -g$(DEBUG) | ||||
| CWARN = -Wall -Wstrict-prototypes | ||||
| CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums | ||||
| #CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
 | ||||
| CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) \
 | ||||
| 	-fno-aggressive-loop-optimizations | ||||
| 
 | ||||
| #ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
 | ||||
| 
 | ||||
| 
 | ||||
| #Additional libraries.
 | ||||
| 
 | ||||
| # Minimalistic printf version
 | ||||
| PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min | ||||
| 
 | ||||
| # Floating point printf version (requires MATH_LIB = -lm below)
 | ||||
| PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt | ||||
| 
 | ||||
| PRINTF_LIB = | ||||
| 
 | ||||
| # Minimalistic scanf version
 | ||||
| SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min | ||||
| 
 | ||||
| # Floating point + %[ scanf version (requires MATH_LIB = -lm below)
 | ||||
| SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt | ||||
| 
 | ||||
| SCANF_LIB = | ||||
| 
 | ||||
| MATH_LIB = -lm | ||||
| 
 | ||||
| # External memory options
 | ||||
| 
 | ||||
| # 64 KB of external RAM, starting after internal RAM (ATmega128!),
 | ||||
| # used for variables (.data/.bss) and heap (malloc()).
 | ||||
| #EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
 | ||||
| 
 | ||||
| # 64 KB of external RAM, starting after internal RAM (ATmega128!),
 | ||||
| # only used for heap (malloc()).
 | ||||
| #EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
 | ||||
| 
 | ||||
| EXTMEMOPTS = | ||||
| 
 | ||||
| #LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
 | ||||
| LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) | ||||
| 
 | ||||
| 
 | ||||
| AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex | ||||
| #AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
 | ||||
| 
 | ||||
| 
 | ||||
| # Uncomment the following if you want avrdude's erase cycle counter.
 | ||||
| # Note that this counter needs to be initialized first using -Yn,
 | ||||
| # see avrdude manual.
 | ||||
| #AVRDUDE_ERASE_COUNTER = -y
 | ||||
| 
 | ||||
| # Uncomment the following if you do /not/ wish a verification to be
 | ||||
| # performed after programming the device.
 | ||||
| #AVRDUDE_NO_VERIFY = -V
 | ||||
| 
 | ||||
| # Increase verbosity level.  Please use this when submitting bug
 | ||||
| # reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
 | ||||
| # to submit bug reports.
 | ||||
| #AVRDUDE_VERBOSE = -v -v
 | ||||
| 
 | ||||
| AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) | ||||
| AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) | ||||
| 
 | ||||
| 
 | ||||
| CC = avr-gcc | ||||
| OBJCOPY = avr-objcopy | ||||
| OBJDUMP = avr-objdump | ||||
| SIZE = avr-size | ||||
| NM = avr-nm | ||||
| AVRDUDE = avrdude | ||||
| REMOVE = rm -f | ||||
| MV = mv -f | ||||
| 
 | ||||
| # Define all object files.
 | ||||
| OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) | ||||
| 
 | ||||
| # Define all listing files.
 | ||||
| LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) | ||||
| 
 | ||||
| # Combine all necessary flags and optional flags.
 | ||||
| # Add target processor to flags.
 | ||||
| ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) | ||||
| ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) | ||||
| 
 | ||||
| 
 | ||||
| # Default target.
 | ||||
| all: build | ||||
| 
 | ||||
| build: elf hex eep | ||||
| 
 | ||||
| elf: $(TARGET).elf | ||||
| hex: $(TARGET).hex | ||||
| eep: $(TARGET).eep | ||||
| lss: $(TARGET).lss | ||||
| sym: $(TARGET).sym | ||||
| 
 | ||||
| 
 | ||||
| # Program the device.
 | ||||
| program: $(TARGET).hex $(TARGET).eep | ||||
| 	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) | ||||
| 
 | ||||
| 
 | ||||
| # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
 | ||||
| COFFCONVERT=$(OBJCOPY) --debugging \
 | ||||
| --change-section-address .data-0x800000 \ | ||||
| --change-section-address .bss-0x800000 \ | ||||
| --change-section-address .noinit-0x800000 \ | ||||
| --change-section-address .eeprom-0x810000 | ||||
| 
 | ||||
| 
 | ||||
| coff: $(TARGET).elf | ||||
| 	$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof | ||||
| 
 | ||||
| 
 | ||||
| extcoff: $(TARGET).elf | ||||
| 	$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof | ||||
| 
 | ||||
| 
 | ||||
| .SUFFIXES: .elf .hex .eep .lss .sym | ||||
| 
 | ||||
| .elf.hex: | ||||
| 	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ | ||||
| 
 | ||||
| .elf.eep: | ||||
| 	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
 | ||||
| 	--change-section-lma .eeprom=0 -O $(FORMAT) $< $@ | ||||
| 
 | ||||
| # Create extended listing file from ELF output file.
 | ||||
| .elf.lss: | ||||
| 	$(OBJDUMP) -h -S $< > $@ | ||||
| 
 | ||||
| # Create a symbol table from ELF output file.
 | ||||
| .elf.sym: | ||||
| 	$(NM) -n $< > $@ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # Link: create ELF output file from object files.
 | ||||
| $(TARGET).elf: $(OBJ) | ||||
| 	$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) | ||||
| 
 | ||||
| 
 | ||||
| # Compile: create object files from C source files.
 | ||||
| .c.o: | ||||
| 	$(CC) -c $(ALL_CFLAGS) $< -o $@ | ||||
| 
 | ||||
| 
 | ||||
| # Compile: create assembler files from C source files.
 | ||||
| .c.s: | ||||
| 	$(CC) -S $(ALL_CFLAGS) $< -o $@ | ||||
| 
 | ||||
| 
 | ||||
| # Assemble: create object files from assembler source files.
 | ||||
| .S.o: | ||||
| 	$(CC) -c $(ALL_ASFLAGS) $< -o $@ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # Target: clean project.
 | ||||
| clean: | ||||
| 	$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
 | ||||
| 	$(TARGET).map $(TARGET).sym $(TARGET).lss \
 | ||||
| 	$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) | ||||
| 
 | ||||
| depend: | ||||
| 	if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
 | ||||
| 	then \
 | ||||
| 		sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
 | ||||
| 			$(MAKEFILE).$$$$ && \
 | ||||
| 		$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
 | ||||
| 	fi | ||||
| 	echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
 | ||||
| 		>> $(MAKEFILE); \
 | ||||
| 	$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) | ||||
| 
 | ||||
| .PHONY:	all build elf hex eep lss sym program coff extcoff clean depend | ||||
| @ -0,0 +1,42 @@ | ||||
| #include "../i2c-slave.h" | ||||
| #include "../serial.h" | ||||
| #include "uno-matrix.h" | ||||
| 
 | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <util/delay.h> | ||||
| 
 | ||||
| void setup(void) { | ||||
|   // give some time for noise to clear
 | ||||
|   _delay_us(1000); | ||||
| 
 | ||||
|   // turn off arduino uno's led on pin 13
 | ||||
|   DDRB |= (1 << 5); | ||||
|   PORTB &= ~(1 << 5); | ||||
| 
 | ||||
|   matrix_init(); | ||||
|   /* i2c_slave_init(0x32); */ | ||||
|   serial_slave_init(); | ||||
| 
 | ||||
|   /* serial_slave_buffer[0] = 0xa1; */ | ||||
|   /* serial_slave_buffer[1] = 0x52; */ | ||||
|   /* serial_slave_buffer[2] = 0xa2; */ | ||||
|   /* serial_slave_buffer[3] = 0x67; */ | ||||
| 
 | ||||
|   // need interrupts for i2c slave code to work
 | ||||
|   sei(); | ||||
| } | ||||
| 
 | ||||
| void loop(void) { | ||||
|   matrix_scan(); | ||||
|   for(int i=0; i<MATRIX_ROWS; ++i) { | ||||
|     slaveBuffer[i] = matrix_get_row(i); | ||||
|     serial_slave_buffer[i] = slaveBuffer[i]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   setup(); | ||||
|   while (1) | ||||
|     loop(); | ||||
| } | ||||
| @ -0,0 +1 @@ | ||||
| Code for Arduino uno (atmega328p) slave used for testing. | ||||
| @ -0,0 +1,160 @@ | ||||
| #define F_CPU 16000000UL | ||||
| 
 | ||||
| #include <util/delay.h> | ||||
| #include <avr/io.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "uno-matrix.h" | ||||
| 
 | ||||
| #define debug(X) NULL | ||||
| #define debug_hex(X) NULL | ||||
| 
 | ||||
| #ifndef DEBOUNCE | ||||
| #   define DEBOUNCE  5 | ||||
| #endif | ||||
| 
 | ||||
| static uint8_t debouncing = DEBOUNCE; | ||||
| 
 | ||||
| /* matrix state(1:on, 0:off) */ | ||||
| static matrix_row_t matrix[MATRIX_ROWS]; | ||||
| static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | ||||
| 
 | ||||
| static matrix_row_t read_cols(void); | ||||
| static void init_cols(void); | ||||
| static void unselect_rows(void); | ||||
| static void select_row(uint8_t row); | ||||
| 
 | ||||
| inline | ||||
| uint8_t matrix_rows(void) | ||||
| { | ||||
|     return MATRIX_ROWS; | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| uint8_t matrix_cols(void) | ||||
| { | ||||
|     return MATRIX_COLS; | ||||
| } | ||||
| 
 | ||||
| void matrix_init(void) | ||||
| { | ||||
|     //debug_enable = true;
 | ||||
|     //debug_matrix = true;
 | ||||
|     //debug_mouse = true;
 | ||||
|     // initialize row and col
 | ||||
|     unselect_rows(); | ||||
|     init_cols(); | ||||
| 
 | ||||
|     // initialize matrix state: all keys off
 | ||||
|     for (uint8_t i=0; i < MATRIX_ROWS; i++) { | ||||
|         matrix[i] = 0; | ||||
|         matrix_debouncing[i] = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t matrix_scan(void) | ||||
| { | ||||
|     for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||||
|         select_row(i); | ||||
|         _delay_us(30);  // without this wait read unstable value.
 | ||||
|         matrix_row_t cols = read_cols(); | ||||
|         //Serial.println(cols, BIN);
 | ||||
|         if (matrix_debouncing[i] != cols) { | ||||
|             matrix_debouncing[i] = cols; | ||||
|             if (debouncing) { | ||||
|                 debug("bounce!: "); debug_hex(debouncing); debug("\n"); | ||||
|             } | ||||
|             debouncing = DEBOUNCE; | ||||
|         } | ||||
|         unselect_rows(); | ||||
|     } | ||||
| 
 | ||||
|     if (debouncing) { | ||||
|         if (--debouncing) { | ||||
|             _delay_ms(1); | ||||
|         } else { | ||||
|             for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||||
|                 matrix[i] = matrix_debouncing[i]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| bool matrix_is_modified(void) | ||||
| { | ||||
|     if (debouncing) return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| bool matrix_is_on(uint8_t row, uint8_t col) | ||||
| { | ||||
|     return (matrix[row] & ((matrix_row_t)1<<col)); | ||||
| } | ||||
| 
 | ||||
| inline | ||||
| matrix_row_t matrix_get_row(uint8_t row) | ||||
| { | ||||
|     return matrix[row]; | ||||
| } | ||||
| 
 | ||||
| // TODO update this comment
 | ||||
| /* Column pin configuration
 | ||||
|  * col: 0   1   2   3   4   5 | ||||
|  * pin: D3  D4  D5  D6  D7  B0 | ||||
|  */ | ||||
| static void  init_cols(void) | ||||
| { | ||||
|     // Input with pull-up(DDR:0, PORT:1)
 | ||||
|   DDRD  &= ~(1<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7); | ||||
|   PORTD |=  (1<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7); | ||||
| 
 | ||||
|   DDRB  &= ~(1<<0); | ||||
|   PORTB |=  (1<<0); | ||||
| } | ||||
| 
 | ||||
| static matrix_row_t read_cols(void) | ||||
| { | ||||
|     return (PIND&(1<<3) ? 0 : (1<<0)) | | ||||
|            (PIND&(1<<4) ? 0 : (1<<1)) | | ||||
|            (PIND&(1<<5) ? 0 : (1<<2)) | | ||||
|            (PIND&(1<<6) ? 0 : (1<<3)) | | ||||
|            (PIND&(1<<7) ? 0 : (1<<4)) | | ||||
|            (PINB&(1<<0) ? 0 : (1<<5)); | ||||
| } | ||||
| 
 | ||||
| /* Row pin configuration
 | ||||
|  * row: 0  1  2  3 | ||||
|  * pin: C0 C1 C2 C3 | ||||
|  */ | ||||
| static void unselect_rows(void) | ||||
| { | ||||
|     // Hi-Z(DDR:0, PORT:0) to unselect
 | ||||
|     DDRC  &= ~0xF; | ||||
|     PORTC &= ~0xF; | ||||
| } | ||||
| 
 | ||||
| static void select_row(uint8_t row) | ||||
| { | ||||
|     // Output low(DDR:1, PORT:0) to select
 | ||||
|     switch (row) { | ||||
|         case 0: | ||||
|             DDRC  |= (1<<0); | ||||
|             PORTC &= ~(1<<0); | ||||
|             break; | ||||
|         case 1: | ||||
|             DDRC  |= (1<<1); | ||||
|             PORTC &= ~(1<<1); | ||||
|             break; | ||||
|         case 2: | ||||
|             DDRC  |= (1<<2); | ||||
|             PORTC &= ~(1<<2); | ||||
|             break; | ||||
|         case 3: | ||||
|             DDRC  |= (1<<3); | ||||
|             PORTC &= ~(1<<3); | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| #ifndef UNO_MATRIX | ||||
| #define UNO_MATRIX | ||||
| 
 | ||||
| #define MATRIX_ROWS 4 | ||||
| #define MATRIX_COLS 6 | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| typedef uint8_t matrix_row_t; | ||||
| 
 | ||||
| uint8_t matrix_rows(void); | ||||
| uint8_t matrix_cols(void); | ||||
| void matrix_init(void); | ||||
| uint8_t matrix_scan(void); | ||||
| bool matrix_is_modified(void); | ||||
| bool matrix_is_on(uint8_t row, uint8_t col); | ||||
| matrix_row_t matrix_get_row(uint8_t row); | ||||
| 
 | ||||
| #endif | ||||
| @ -0,0 +1,377 @@ | ||||
| /* Name: usbconfig.h
 | ||||
|  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||
|  * Author: Christian Starkjohann | ||||
|  * Creation Date: 2005-04-01 | ||||
|  * Tabsize: 4 | ||||
|  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||
|  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||
|  * This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $ | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __usbconfig_h_included__ | ||||
| #define __usbconfig_h_included__ | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| General Description: | ||||
| This file is an example configuration (with inline documentation) for the USB | ||||
| driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is | ||||
| also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may | ||||
| wire the lines to any other port, as long as D+ is also wired to INT0 (or any | ||||
| other hardware interrupt, as long as it is the highest level interrupt, see | ||||
| section at the end of this file). | ||||
| */ | ||||
| 
 | ||||
| /* ---------------------------- Hardware Config ---------------------------- */ | ||||
| 
 | ||||
| #define USB_CFG_IOPORTNAME      D | ||||
| /* This is the port where the USB bus is connected. When you configure it to
 | ||||
|  * "B", the registers PORTB, PINB and DDRB will be used. | ||||
|  */ | ||||
| #define USB_CFG_DMINUS_BIT      3 | ||||
| /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 | ||||
|  * This may be any bit in the port. | ||||
|  */ | ||||
| #define USB_CFG_DPLUS_BIT       2 | ||||
| /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 | ||||
|  * This may be any bit in the port. Please note that D+ must also be connected | ||||
|  * to interrupt pin INT0! [You can also use other interrupts, see section | ||||
|  * "Optional MCU Description" below, or you can connect D- to the interrupt, as | ||||
|  * it is required if you use the USB_COUNT_SOF feature. If you use D- for the | ||||
|  * interrupt, the USB interrupt will also be triggered at Start-Of-Frame | ||||
|  * markers every millisecond.] | ||||
|  */ | ||||
| #define USB_CFG_CLOCK_KHZ       (F_CPU/1000) | ||||
| /* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
 | ||||
|  * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code | ||||
|  * require no crystal, they tolerate +/- 1% deviation from the nominal | ||||
|  * frequency. All other rates require a precision of 2000 ppm and thus a | ||||
|  * crystal! | ||||
|  * Since F_CPU should be defined to your actual clock rate anyway, you should | ||||
|  * not need to modify this setting. | ||||
|  */ | ||||
| #define USB_CFG_CHECK_CRC       0 | ||||
| /* Define this to 1 if you want that the driver checks integrity of incoming
 | ||||
|  * data packets (CRC checks). CRC checks cost quite a bit of code size and are | ||||
|  * currently only available for 18 MHz crystal clock. You must choose | ||||
|  * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. | ||||
|  */ | ||||
| 
 | ||||
| /* ----------------------- Optional Hardware Config ------------------------ */ | ||||
| 
 | ||||
| /* #define USB_CFG_PULLUP_IOPORTNAME   D */ | ||||
| /* If you connect the 1.5k pullup resistor from D- to a port pin instead of
 | ||||
|  * V+, you can connect and disconnect the device from firmware by calling | ||||
|  * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). | ||||
|  * This constant defines the port on which the pullup resistor is connected. | ||||
|  */ | ||||
| /* #define USB_CFG_PULLUP_BIT          4 */ | ||||
| /* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
 | ||||
|  * above) where the 1.5k pullup resistor is connected. See description | ||||
|  * above for details. | ||||
|  */ | ||||
| 
 | ||||
| /* --------------------------- Functional Range ---------------------------- */ | ||||
| 
 | ||||
| #define USB_CFG_HAVE_INTRIN_ENDPOINT    1 | ||||
| /* Define this to 1 if you want to compile a version with two endpoints: The
 | ||||
|  * default control endpoint 0 and an interrupt-in endpoint (any other endpoint | ||||
|  * number). | ||||
|  */ | ||||
| #define USB_CFG_HAVE_INTRIN_ENDPOINT3   1 | ||||
| /* Define this to 1 if you want to compile a version with three endpoints: The
 | ||||
|  * default control endpoint 0, an interrupt-in endpoint 3 (or the number | ||||
|  * configured below) and a catch-all default interrupt-in endpoint as above. | ||||
|  * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. | ||||
|  */ | ||||
| #define USB_CFG_EP3_NUMBER              3 | ||||
| /* If the so-called endpoint 3 is used, it can now be configured to any other
 | ||||
|  * endpoint number (except 0) with this macro. Default if undefined is 3. | ||||
|  */ | ||||
| /* #define USB_INITIAL_DATATOKEN           USBPID_DATA1 */ | ||||
| /* The above macro defines the startup condition for data toggling on the
 | ||||
|  * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. | ||||
|  * Since the token is toggled BEFORE sending any data, the first packet is | ||||
|  * sent with the oposite value of this configuration! | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_HALT          0 | ||||
| /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
 | ||||
|  * for endpoint 1 (interrupt endpoint). Although you may not need this feature, | ||||
|  * it is required by the standard. We have made it a config option because it | ||||
|  * bloats the code considerably. | ||||
|  */ | ||||
| #define USB_CFG_SUPPRESS_INTR_CODE      0 | ||||
| /* Define this to 1 if you want to declare interrupt-in endpoints, but don't
 | ||||
|  * want to send any data over them. If this macro is defined to 1, functions | ||||
|  * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if | ||||
|  * you need the interrupt-in endpoints in order to comply to an interface | ||||
|  * (e.g. HID), but never want to send any data. This option saves a couple | ||||
|  * of bytes in flash memory and the transmit buffers in RAM. | ||||
|  */ | ||||
| #define USB_CFG_INTR_POLL_INTERVAL      10 | ||||
| /* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 | ||||
|  * interval. The value is in milliseconds and must not be less than 10 ms for | ||||
|  * low speed devices. | ||||
|  */ | ||||
| #define USB_CFG_IS_SELF_POWERED         0 | ||||
| /* Define this to 1 if the device has its own power supply. Set it to 0 if the
 | ||||
|  * device is powered from the USB bus. | ||||
|  */ | ||||
| #define USB_CFG_MAX_BUS_POWER           100 | ||||
| /* Set this variable to the maximum USB bus power consumption of your device.
 | ||||
|  * The value is in milliamperes. [It will be divided by two since USB | ||||
|  * communicates power requirements in units of 2 mA.] | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_WRITE      1 | ||||
| /* Set this to 1 if you want usbFunctionWrite() to be called for control-out
 | ||||
|  * transfers. Set it to 0 if you don't need it and want to save a couple of | ||||
|  * bytes. | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_READ       0 | ||||
| /* Set this to 1 if you need to send control replies which are generated
 | ||||
|  * "on the fly" when usbFunctionRead() is called. If you only want to send | ||||
|  * data from a static buffer, set it to 0 and return the data from | ||||
|  * usbFunctionSetup(). This saves a couple of bytes. | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_WRITEOUT   0 | ||||
| /* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
 | ||||
|  * You must implement the function usbFunctionWriteOut() which receives all | ||||
|  * interrupt/bulk data sent to any endpoint other than 0. The endpoint number | ||||
|  * can be found in 'usbRxToken'. | ||||
|  */ | ||||
| #define USB_CFG_HAVE_FLOWCONTROL        0 | ||||
| /* Define this to 1 if you want flowcontrol over USB data. See the definition
 | ||||
|  * of the macros usbDisableAllRequests() and usbEnableAllRequests() in | ||||
|  * usbdrv.h. | ||||
|  */ | ||||
| #define USB_CFG_DRIVER_FLASH_PAGE       0 | ||||
| /* If the device has more than 64 kBytes of flash, define this to the 64 k page
 | ||||
|  * where the driver's constants (descriptors) are located. Or in other words: | ||||
|  * Define this to 1 for boot loaders on the ATMega128. | ||||
|  */ | ||||
| #define USB_CFG_LONG_TRANSFERS          0 | ||||
| /* Define this to 1 if you want to send/receive blocks of more than 254 bytes
 | ||||
|  * in a single control-in or control-out transfer. Note that the capability | ||||
|  * for long transfers increases the driver size. | ||||
|  */ | ||||
| /* #define USB_RX_USER_HOOK(data, len)     if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ | ||||
| /* This macro is a hook if you want to do unconventional things. If it is
 | ||||
|  * defined, it's inserted at the beginning of received message processing. | ||||
|  * If you eat the received message and don't want default processing to | ||||
|  * proceed, do a return after doing your things. One possible application | ||||
|  * (besides debugging) is to flash a status LED on each packet. | ||||
|  */ | ||||
| /* #define USB_RESET_HOOK(resetStarts)     if(!resetStarts){hadUsbReset();} */ | ||||
| /* This macro is a hook if you need to know when an USB RESET occurs. It has
 | ||||
|  * one parameter which distinguishes between the start of RESET state and its | ||||
|  * end. | ||||
|  */ | ||||
| /* #define USB_SET_ADDRESS_HOOK()              hadAddressAssigned(); */ | ||||
| /* This macro (if defined) is executed when a USB SET_ADDRESS request was
 | ||||
|  * received. | ||||
|  */ | ||||
| #define USB_COUNT_SOF                   0 | ||||
| /* define this macro to 1 if you need the global variable "usbSofCount" which
 | ||||
|  * counts SOF packets. This feature requires that the hardware interrupt is | ||||
|  * connected to D- instead of D+. | ||||
|  */ | ||||
| /* #ifdef __ASSEMBLER__
 | ||||
|  * macro myAssemblerMacro | ||||
|  *     in      YL, TCNT0 | ||||
|  *     sts     timer0Snapshot, YL | ||||
|  *     endm | ||||
|  * #endif | ||||
|  * #define USB_SOF_HOOK                    myAssemblerMacro | ||||
|  * This macro (if defined) is executed in the assembler module when a | ||||
|  * Start Of Frame condition is detected. It is recommended to define it to | ||||
|  * the name of an assembler macro which is defined here as well so that more | ||||
|  * than one assembler instruction can be used. The macro may use the register | ||||
|  * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages | ||||
|  * immediately after an SOF pulse may be lost and must be retried by the host. | ||||
|  * What can you do with this hook? Since the SOF signal occurs exactly every | ||||
|  * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in | ||||
|  * designs running on the internal RC oscillator. | ||||
|  * Please note that Start Of Frame detection works only if D- is wired to the | ||||
|  * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! | ||||
|  */ | ||||
| #define USB_CFG_CHECK_DATA_TOGGLING     0 | ||||
| /* define this macro to 1 if you want to filter out duplicate data packets
 | ||||
|  * sent by the host. Duplicates occur only as a consequence of communication | ||||
|  * errors, when the host does not receive an ACK. Please note that you need to | ||||
|  * implement the filtering yourself in usbFunctionWriteOut() and | ||||
|  * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable | ||||
|  * for each control- and out-endpoint to check for duplicate packets. | ||||
|  */ | ||||
| #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   0 | ||||
| /* define this macro to 1 if you want the function usbMeasureFrameLength()
 | ||||
|  * compiled in. This function can be used to calibrate the AVR's RC oscillator. | ||||
|  */ | ||||
| #define USB_USE_FAST_CRC                0 | ||||
| /* The assembler module has two implementations for the CRC algorithm. One is
 | ||||
|  * faster, the other is smaller. This CRC routine is only used for transmitted | ||||
|  * messages where timing is not critical. The faster routine needs 31 cycles | ||||
|  * per byte while the smaller one needs 61 to 69 cycles. The faster routine | ||||
|  * may be worth the 32 bytes bigger code size if you transmit lots of data and | ||||
|  * run the AVR close to its limit. | ||||
|  */ | ||||
| 
 | ||||
| /* -------------------------- Device Description --------------------------- */ | ||||
| 
 | ||||
| #define USB_CFG_VENDOR_ID       (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF) | ||||
| /* USB vendor ID for the device, low byte first. If you have registered your
 | ||||
|  * own Vendor ID, define it here. Otherwise you may use one of obdev's free | ||||
|  * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! | ||||
|  * *** IMPORTANT NOTE *** | ||||
|  * This template uses obdev's shared VID/PID pair for Vendor Class devices | ||||
|  * with libusb: 0x16c0/0x5dc.  Use this VID/PID pair ONLY if you understand | ||||
|  * the implications! | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_ID       (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF) | ||||
| /* This is the ID of the product, low byte first. It is interpreted in the
 | ||||
|  * scope of the vendor ID. If you have registered your own VID with usb.org | ||||
|  * or if you have licensed a PID from somebody else, define it here. Otherwise | ||||
|  * you may use one of obdev's free shared VID/PID pairs. See the file | ||||
|  * USB-IDs-for-free.txt for details! | ||||
|  * *** IMPORTANT NOTE *** | ||||
|  * This template uses obdev's shared VID/PID pair for Vendor Class devices | ||||
|  * with libusb: 0x16c0/0x5dc.  Use this VID/PID pair ONLY if you understand | ||||
|  * the implications! | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_VERSION  0x00, 0x01 | ||||
| /* Version number of the device: Minor number first, then major number.
 | ||||
|  */ | ||||
| #define USB_CFG_VENDOR_NAME     't', '.', 'm', '.', 'k', '.' | ||||
| #define USB_CFG_VENDOR_NAME_LEN 6 | ||||
| /* These two values define the vendor name returned by the USB device. The name
 | ||||
|  * must be given as a list of characters under single quotes. The characters | ||||
|  * are interpreted as Unicode (UTF-16) entities. | ||||
|  * If you don't want a vendor name string, undefine these macros. | ||||
|  * ALWAYS define a vendor name containing your Internet domain name if you use | ||||
|  * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for | ||||
|  * details. | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_NAME     'P', 'S', '/', '2', ' ', 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd', ' ', 'c', 'o', 'n', 'v', 'e', 'r', 't', 'e', 'r' | ||||
| #define USB_CFG_DEVICE_NAME_LEN 23 | ||||
| /* Same as above for the device name. If you don't want a device name, undefine
 | ||||
|  * the macros. See the file USB-IDs-for-free.txt before you assign a name if | ||||
|  * you use a shared VID/PID. | ||||
|  */ | ||||
| /*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */ | ||||
| /*#define USB_CFG_SERIAL_NUMBER_LEN   0 */ | ||||
| /* Same as above for the serial number. If you don't want a serial number,
 | ||||
|  * undefine the macros. | ||||
|  * It may be useful to provide the serial number through other means than at | ||||
|  * compile time. See the section about descriptor properties below for how | ||||
|  * to fine tune control over USB descriptors such as the string descriptor | ||||
|  * for the serial number. | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_CLASS        0 | ||||
| #define USB_CFG_DEVICE_SUBCLASS     0 | ||||
| /* See USB specification if you want to conform to an existing device class.
 | ||||
|  * Class 0xff is "vendor specific". | ||||
|  */ | ||||
| #define USB_CFG_INTERFACE_CLASS     3   /* HID */ | ||||
| #define USB_CFG_INTERFACE_SUBCLASS  1   /* Boot */ | ||||
| #define USB_CFG_INTERFACE_PROTOCOL  1   /* Keyboard */ | ||||
| /* See USB specification if you want to conform to an existing device class or
 | ||||
|  * protocol. The following classes must be set at interface level: | ||||
|  * HID class is 3, no subclass and protocol required (but may be useful!) | ||||
|  * CDC class is 2, use subclass 2 and protocol 1 for ACM | ||||
|  */ | ||||
| #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    0 | ||||
| /* Define this to the length of the HID report descriptor, if you implement
 | ||||
|  * an HID device. Otherwise don't define it or define it to 0. | ||||
|  * If you use this define, you must add a PROGMEM character array named | ||||
|  * "usbHidReportDescriptor" to your code which contains the report descriptor. | ||||
|  * Don't forget to keep the array and this define in sync! | ||||
|  */ | ||||
| 
 | ||||
| /* #define USB_PUBLIC static */ | ||||
| /* Use the define above if you #include usbdrv.c instead of linking against it.
 | ||||
|  * This technique saves a couple of bytes in flash memory. | ||||
|  */ | ||||
| 
 | ||||
| /* ------------------- Fine Control over USB Descriptors ------------------- */ | ||||
| /* If you don't want to use the driver's default USB descriptors, you can
 | ||||
|  * provide our own. These can be provided as (1) fixed length static data in | ||||
|  * flash memory, (2) fixed length static data in RAM or (3) dynamically at | ||||
|  * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more | ||||
|  * information about this function. | ||||
|  * Descriptor handling is configured through the descriptor's properties. If | ||||
|  * no properties are defined or if they are 0, the default descriptor is used. | ||||
|  * Possible properties are: | ||||
|  *   + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched | ||||
|  *     at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is | ||||
|  *     used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if | ||||
|  *     you want RAM pointers. | ||||
|  *   + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found | ||||
|  *     in static memory is in RAM, not in flash memory. | ||||
|  *   + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), | ||||
|  *     the driver must know the descriptor's length. The descriptor itself is | ||||
|  *     found at the address of a well known identifier (see below). | ||||
|  * List of static descriptor names (must be declared PROGMEM if in flash): | ||||
|  *   char usbDescriptorDevice[]; | ||||
|  *   char usbDescriptorConfiguration[]; | ||||
|  *   char usbDescriptorHidReport[]; | ||||
|  *   char usbDescriptorString0[]; | ||||
|  *   int usbDescriptorStringVendor[]; | ||||
|  *   int usbDescriptorStringDevice[]; | ||||
|  *   int usbDescriptorStringSerialNumber[]; | ||||
|  * Other descriptors can't be provided statically, they must be provided | ||||
|  * dynamically at runtime. | ||||
|  * | ||||
|  * Descriptor properties are or-ed or added together, e.g.: | ||||
|  * #define USB_CFG_DESCR_PROPS_DEVICE   (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) | ||||
|  * | ||||
|  * The following descriptors are defined: | ||||
|  *   USB_CFG_DESCR_PROPS_DEVICE | ||||
|  *   USB_CFG_DESCR_PROPS_CONFIGURATION | ||||
|  *   USB_CFG_DESCR_PROPS_STRINGS | ||||
|  *   USB_CFG_DESCR_PROPS_STRING_0 | ||||
|  *   USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||
|  *   USB_CFG_DESCR_PROPS_STRING_PRODUCT | ||||
|  *   USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||
|  *   USB_CFG_DESCR_PROPS_HID | ||||
|  *   USB_CFG_DESCR_PROPS_HID_REPORT | ||||
|  *   USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) | ||||
|  * | ||||
|  * Note about string descriptors: String descriptors are not just strings, they | ||||
|  * are Unicode strings prefixed with a 2 byte header. Example: | ||||
|  * int  serialNumberDescriptor[] = { | ||||
|  *     USB_STRING_DESCRIPTOR_HEADER(6), | ||||
|  *     'S', 'e', 'r', 'i', 'a', 'l' | ||||
|  * }; | ||||
|  */ | ||||
| 
 | ||||
| #define USB_CFG_DESCR_PROPS_DEVICE                  0 | ||||
| #define USB_CFG_DESCR_PROPS_CONFIGURATION           USB_PROP_IS_DYNAMIC | ||||
| //#define USB_CFG_DESCR_PROPS_CONFIGURATION           0
 | ||||
| #define USB_CFG_DESCR_PROPS_STRINGS                 0 | ||||
| #define USB_CFG_DESCR_PROPS_STRING_0                0 | ||||
| #define USB_CFG_DESCR_PROPS_STRING_VENDOR           0 | ||||
| #define USB_CFG_DESCR_PROPS_STRING_PRODUCT          0 | ||||
| #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0 | ||||
| //#define USB_CFG_DESCR_PROPS_HID                     USB_PROP_IS_DYNAMIC
 | ||||
| #define USB_CFG_DESCR_PROPS_HID                     0 | ||||
| #define USB_CFG_DESCR_PROPS_HID_REPORT              USB_PROP_IS_DYNAMIC | ||||
| //#define USB_CFG_DESCR_PROPS_HID_REPORT              0
 | ||||
| #define USB_CFG_DESCR_PROPS_UNKNOWN                 0 | ||||
| 
 | ||||
| /* ----------------------- Optional MCU Description ------------------------ */ | ||||
| 
 | ||||
| /* The following configurations have working defaults in usbdrv.h. You
 | ||||
|  * usually don't need to set them explicitly. Only if you want to run | ||||
|  * the driver on a device which is not yet supported or with a compiler | ||||
|  * which is not fully supported (such as IAR C) or if you use a differnt | ||||
|  * interrupt than INT0, you may have to define some of these. | ||||
|  */ | ||||
| /* #define USB_INTR_CFG            MCUCR */ | ||||
| /* #define USB_INTR_CFG_SET        ((1 << ISC00) | (1 << ISC01)) */ | ||||
| /* #define USB_INTR_CFG_CLR        0 */ | ||||
| /* #define USB_INTR_ENABLE         GIMSK */ | ||||
| /* #define USB_INTR_ENABLE_BIT     INT0 */ | ||||
| /* #define USB_INTR_PENDING        GIFR */ | ||||
| /* #define USB_INTR_PENDING_BIT    INTF0 */ | ||||
| /* #define USB_INTR_VECTOR         INT0_vect */ | ||||
| 
 | ||||
| #endif /* __usbconfig_h_included__ */ | ||||
					Loading…
					
					
				
		Reference in new issue
	
	 Jack Humbert
						Jack Humbert