parent
f02430b131
commit
52f4a38cb3
@ -0,0 +1,3 @@
|
|||||||
|
ifndef MAKEFILE_INCLUDED
|
||||||
|
include ../../../Makefile
|
||||||
|
endif
|
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef ERGODOX_ERGODONE_CONFIG_H
|
||||||
|
#define ERGODOX_ERGODONE_CONFIG_H
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
#include "config_common.h"
|
||||||
|
|
||||||
|
/* USB Device descriptor parameter */
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0x1307
|
||||||
|
#define DEVICE_VER 0x0001
|
||||||
|
#define MANUFACTURER ErgoDone
|
||||||
|
#define PRODUCT ErgoDone
|
||||||
|
#define DESCRIPTION QMK keyboard firmware for ErgoDone
|
||||||
|
|
||||||
|
/* key matrix size */
|
||||||
|
#define MATRIX_ROWS 6
|
||||||
|
#define MATRIX_COLS 14
|
||||||
|
|
||||||
|
/* fix space cadet rollover issue */
|
||||||
|
#define DISABLE_SPACE_CADET_ROLLOVER
|
||||||
|
|
||||||
|
/* Set 0 if debouncing isn't needed */
|
||||||
|
#define DEBOUNCE 5
|
||||||
|
|
||||||
|
#define PREVENT_STUCK_MODIFIERS
|
||||||
|
|
||||||
|
#define USB_MAX_POWER_CONSUMPTION 500
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature disable options
|
||||||
|
* These options are also useful to firmware size reduction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* disable debug print */
|
||||||
|
// #define NO_DEBUG
|
||||||
|
|
||||||
|
/* disable print */
|
||||||
|
// #define NO_PRINT
|
||||||
|
|
||||||
|
/* disable action features */
|
||||||
|
//#define NO_ACTION_LAYER
|
||||||
|
//#define NO_ACTION_TAPPING
|
||||||
|
//#define NO_ACTION_ONESHOT
|
||||||
|
//#define NO_ACTION_MACRO
|
||||||
|
//#define NO_ACTION_FUNCTION
|
||||||
|
//#define DEBUG_MATRIX_SCAN_RATE
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,5 @@
|
|||||||
|
#include "ergodone.h"
|
||||||
|
|
||||||
|
void matrix_init_kb(void) {
|
||||||
|
matrix_init_user();
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef ERGODOX_ERGODONE_H
|
||||||
|
#define ERGODOX_ERGODONE_H
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
|
||||||
|
#define CPU_16MHz 0x00
|
||||||
|
|
||||||
|
void init_ergodox(void);
|
||||||
|
|
||||||
|
inline void ergodox_right_led_1_off(void) {}
|
||||||
|
inline void ergodox_right_led_1_on(void) {}
|
||||||
|
inline void ergodox_right_led_2_off(void) {}
|
||||||
|
inline void ergodox_right_led_2_on(void) {}
|
||||||
|
inline void ergodox_right_led_3_off(void) {}
|
||||||
|
inline void ergodox_right_led_3_on(void) {}
|
||||||
|
inline void ergodox_board_led_off(void) {}
|
||||||
|
inline void ergodox_board_led_on(void) {}
|
||||||
|
|
||||||
|
#define KEYMAP( \
|
||||||
|
\
|
||||||
|
/* left hand, spatial positions */ \
|
||||||
|
k00,k01,k02,k03,k04,k05,k06, \
|
||||||
|
k10,k11,k12,k13,k14,k15,k16, \
|
||||||
|
k20,k21,k22,k23,k24,k25, \
|
||||||
|
k30,k31,k32,k33,k34,k35,k36, \
|
||||||
|
k40,k41,k42,k43,k44, \
|
||||||
|
k55,k56, \
|
||||||
|
k54, \
|
||||||
|
k53,k52,k51, \
|
||||||
|
\
|
||||||
|
/* right hand, spatial positions */ \
|
||||||
|
k07,k08,k09,k0A,k0B,k0C,k0D, \
|
||||||
|
k17,k18,k19,k1A,k1B,k1C,k1D, \
|
||||||
|
k28,k29,k2A,k2B,k2C,k2D, \
|
||||||
|
k37,k38,k39,k3A,k3B,k3C,k3D, \
|
||||||
|
k49,k4A,k4B,k4C,k4D, \
|
||||||
|
k57,k58, \
|
||||||
|
k59, \
|
||||||
|
k5C,k5B,k5A ) \
|
||||||
|
\
|
||||||
|
/* matrix positions */ \
|
||||||
|
{ \
|
||||||
|
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, k0C, k0D }, \
|
||||||
|
{ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, k1C, k1D }, \
|
||||||
|
{ k20, k21, k22, k23, k24, k25, KC_NO, KC_NO, k28, k29, k2A, k2B, k2C, k2D }, \
|
||||||
|
{ k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3A, k3B, k3C, k3D }, \
|
||||||
|
{ k40, k41, k42, k43, k44, KC_NO, KC_NO, KC_NO, KC_NO, k49, k4A, k4B, k4C, k4D }, \
|
||||||
|
{ KC_NO, k51, k52, k53, k54, k55, k56, k57, k58, k59, k5A, k5B, k5C, KC_NO } \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,120 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include "action.h"
|
||||||
|
#include "i2cmaster.h"
|
||||||
|
#include "expander.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
static uint8_t expander_status = 0;
|
||||||
|
static uint8_t expander_input = 0;
|
||||||
|
|
||||||
|
void expander_config(void);
|
||||||
|
uint8_t expander_write(uint8_t reg, uint8_t data);
|
||||||
|
uint8_t expander_read(uint8_t reg, uint8_t *data);
|
||||||
|
|
||||||
|
void expander_init(void)
|
||||||
|
{
|
||||||
|
i2c_init();
|
||||||
|
expander_scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void expander_scan(void)
|
||||||
|
{
|
||||||
|
dprintf("expander status: %d ... ", expander_status);
|
||||||
|
uint8_t ret = i2c_start(EXPANDER_ADDR | I2C_WRITE);
|
||||||
|
if (ret == 0) {
|
||||||
|
i2c_stop();
|
||||||
|
if (expander_status == 0) {
|
||||||
|
dprintf("attached\n");
|
||||||
|
expander_status = 1;
|
||||||
|
expander_config();
|
||||||
|
clear_keyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (expander_status == 1) {
|
||||||
|
dprintf("detached\n");
|
||||||
|
expander_status = 0;
|
||||||
|
clear_keyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dprintf("%d\n", expander_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expander_read_cols(void)
|
||||||
|
{
|
||||||
|
expander_read(EXPANDER_REG_GPIOA, &expander_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t expander_get_col(uint8_t col)
|
||||||
|
{
|
||||||
|
if (col > 4) {
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
return expander_input & (1<<col) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix_row_t expander_read_row(void)
|
||||||
|
{
|
||||||
|
expander_read_cols();
|
||||||
|
|
||||||
|
/* make cols */
|
||||||
|
matrix_row_t cols = 0;
|
||||||
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
||||||
|
if (expander_get_col(col)) {
|
||||||
|
cols |= (1UL << (MATRIX_COLS - 1 - col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
void expander_unselect_rows(void)
|
||||||
|
{
|
||||||
|
expander_write(EXPANDER_REG_IODIRB, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expander_select_row(uint8_t row)
|
||||||
|
{
|
||||||
|
expander_write(EXPANDER_REG_IODIRB, ~(1<<(row+1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void expander_config(void)
|
||||||
|
{
|
||||||
|
expander_write(EXPANDER_REG_IPOLA, 0xFF);
|
||||||
|
expander_write(EXPANDER_REG_GPPUA, 0xFF);
|
||||||
|
expander_write(EXPANDER_REG_IODIRB, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t expander_write(uint8_t reg, uint8_t data)
|
||||||
|
{
|
||||||
|
if (expander_status == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t ret;
|
||||||
|
ret = i2c_start(EXPANDER_ADDR | I2C_WRITE);
|
||||||
|
if (ret) goto stop;
|
||||||
|
ret = i2c_write(reg);
|
||||||
|
if (ret) goto stop;
|
||||||
|
ret = i2c_write(data);
|
||||||
|
stop:
|
||||||
|
i2c_stop();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t expander_read(uint8_t reg, uint8_t *data)
|
||||||
|
{
|
||||||
|
if (expander_status == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t ret;
|
||||||
|
ret = i2c_start(EXPANDER_ADDR | I2C_WRITE);
|
||||||
|
if (ret) goto stop;
|
||||||
|
ret = i2c_write(reg);
|
||||||
|
if (ret) goto stop;
|
||||||
|
ret = i2c_rep_start(EXPANDER_ADDR | I2C_READ);
|
||||||
|
if (ret) goto stop;
|
||||||
|
*data = i2c_readNak();
|
||||||
|
stop:
|
||||||
|
i2c_stop();
|
||||||
|
return ret;
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef EXPANDER_H
|
||||||
|
#define EXPANDER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
|
#define MCP23017
|
||||||
|
#define MCP23017_A0 0
|
||||||
|
#define MCP23017_A1 0
|
||||||
|
#define MCP23017_A2 0
|
||||||
|
|
||||||
|
#ifdef MCP23017
|
||||||
|
#define EXPANDER_ADDR ((0x20|(MCP23017_A0<<0)|(MCP23017_A1<<1)|(MCP23017_A2<<2)) << 1)
|
||||||
|
enum EXPANDER_REG_BANK0 {
|
||||||
|
EXPANDER_REG_IODIRA = 0,
|
||||||
|
EXPANDER_REG_IODIRB,
|
||||||
|
EXPANDER_REG_IPOLA,
|
||||||
|
EXPANDER_REG_IPOLB,
|
||||||
|
EXPANDER_REG_GPINTENA,
|
||||||
|
EXPANDER_REG_GPINTENB,
|
||||||
|
EXPANDER_REG_DEFVALA,
|
||||||
|
EXPANDER_REG_DEFVALB,
|
||||||
|
EXPANDER_REG_INTCONA,
|
||||||
|
EXPANDER_REG_INTCONB,
|
||||||
|
EXPANDER_REG_IOCONA,
|
||||||
|
EXPANDER_REG_IOCONB,
|
||||||
|
EXPANDER_REG_GPPUA,
|
||||||
|
EXPANDER_REG_GPPUB,
|
||||||
|
EXPANDER_REG_INTFA,
|
||||||
|
EXPANDER_REG_INTFB,
|
||||||
|
EXPANDER_REG_INTCAPA,
|
||||||
|
EXPANDER_REG_INTCAPB,
|
||||||
|
EXPANDER_REG_GPIOA,
|
||||||
|
EXPANDER_REG_GPIOB,
|
||||||
|
EXPANDER_REG_OLATA,
|
||||||
|
EXPANDER_REG_OLATB
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void expander_init(void);
|
||||||
|
void expander_scan(void);
|
||||||
|
void expander_read_cols(void);
|
||||||
|
uint8_t expander_get_col(uint8_t col);
|
||||||
|
matrix_row_t expander_read_row(void);
|
||||||
|
void expander_unselect_rows(void);
|
||||||
|
void expander_select_row(uint8_t row);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,178 @@
|
|||||||
|
#ifndef _I2CMASTER_H
|
||||||
|
#define _I2CMASTER_H 1
|
||||||
|
/*************************************************************************
|
||||||
|
* Title: C include file for the I2C master interface
|
||||||
|
* (i2cmaster.S or twimaster.c)
|
||||||
|
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||||||
|
* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $
|
||||||
|
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
|
||||||
|
* Target: any AVR device
|
||||||
|
* Usage: see Doxygen manual
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifdef DOXYGEN
|
||||||
|
/**
|
||||||
|
@defgroup pfleury_ic2master I2C Master library
|
||||||
|
@code #include <i2cmaster.h> @endcode
|
||||||
|
|
||||||
|
@brief I2C (TWI) Master Software Library
|
||||||
|
|
||||||
|
Basic routines for communicating with I2C slave devices. This single master
|
||||||
|
implementation is limited to one bus master on the I2C bus.
|
||||||
|
|
||||||
|
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
|
||||||
|
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
|
||||||
|
Since the API for these two implementations is exactly the same, an application can be linked either against the
|
||||||
|
software I2C implementation or the hardware I2C implementation.
|
||||||
|
|
||||||
|
Use 4.7k pull-up resistor on the SDA and SCL pin.
|
||||||
|
|
||||||
|
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
|
||||||
|
i2cmaster.S to your target when using the software I2C implementation !
|
||||||
|
|
||||||
|
Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
|
||||||
|
|
||||||
|
@note
|
||||||
|
The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
|
||||||
|
to GNU assembler and AVR-GCC C call interface.
|
||||||
|
Replaced the incorrect quarter period delays found in AVR300 with
|
||||||
|
half period delays.
|
||||||
|
|
||||||
|
@author Peter Fleury pfleury@gmx.ch http://jump.to/fleury
|
||||||
|
|
||||||
|
@par API Usage Example
|
||||||
|
The following code shows typical usage of this library, see example test_i2cmaster.c
|
||||||
|
|
||||||
|
@code
|
||||||
|
|
||||||
|
#include <i2cmaster.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned char ret;
|
||||||
|
|
||||||
|
i2c_init(); // initialize I2C library
|
||||||
|
|
||||||
|
// write 0x75 to EEPROM address 5 (Byte Write)
|
||||||
|
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
|
||||||
|
i2c_write(0x05); // write address = 5
|
||||||
|
i2c_write(0x75); // write value 0x75 to EEPROM
|
||||||
|
i2c_stop(); // set stop conditon = release bus
|
||||||
|
|
||||||
|
|
||||||
|
// read previously written value back from EEPROM address 5
|
||||||
|
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
|
||||||
|
|
||||||
|
i2c_write(0x05); // write address = 5
|
||||||
|
i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode
|
||||||
|
|
||||||
|
ret = i2c_readNak(); // read one byte from EEPROM
|
||||||
|
i2c_stop();
|
||||||
|
|
||||||
|
for(;;);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
*/
|
||||||
|
#endif /* DOXYGEN */
|
||||||
|
|
||||||
|
/**@{*/
|
||||||
|
|
||||||
|
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
|
||||||
|
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
|
||||||
|
#define I2C_READ 1
|
||||||
|
|
||||||
|
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
|
||||||
|
#define I2C_WRITE 0
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief initialize the I2C master interace. Need to be called only once
|
||||||
|
@param void
|
||||||
|
@return none
|
||||||
|
*/
|
||||||
|
extern void i2c_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Terminates the data transfer and releases the I2C bus
|
||||||
|
@param void
|
||||||
|
@return none
|
||||||
|
*/
|
||||||
|
extern void i2c_stop(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Issues a start condition and sends address and transfer direction
|
||||||
|
|
||||||
|
@param addr address and transfer direction of I2C device
|
||||||
|
@retval 0 device accessible
|
||||||
|
@retval 1 failed to access device
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_start(unsigned char addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Issues a repeated start condition and sends address and transfer direction
|
||||||
|
|
||||||
|
@param addr address and transfer direction of I2C device
|
||||||
|
@retval 0 device accessible
|
||||||
|
@retval 1 failed to access device
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_rep_start(unsigned char addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Issues a start condition and sends address and transfer direction
|
||||||
|
|
||||||
|
If device is busy, use ack polling to wait until device ready
|
||||||
|
@param addr address and transfer direction of I2C device
|
||||||
|
@return none
|
||||||
|
*/
|
||||||
|
extern void i2c_start_wait(unsigned char addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Send one byte to I2C device
|
||||||
|
@param data byte to be transfered
|
||||||
|
@retval 0 write successful
|
||||||
|
@retval 1 write failed
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_write(unsigned char data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief read one byte from the I2C device, request more data from device
|
||||||
|
@return byte read from I2C device
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_readAck(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief read one byte from the I2C device, read is followed by a stop condition
|
||||||
|
@return byte read from I2C device
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_readNak(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief read one byte from the I2C device
|
||||||
|
|
||||||
|
Implemented as a macro, which calls either i2c_readAck or i2c_readNak
|
||||||
|
|
||||||
|
@param ack 1 send ack, request more data from device<br>
|
||||||
|
0 send nak, read is followed by a stop condition
|
||||||
|
@return byte read from I2C device
|
||||||
|
*/
|
||||||
|
extern unsigned char i2c_read(unsigned char ack);
|
||||||
|
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
|
||||||
|
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
#endif
|
@ -0,0 +1,295 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "wait.h"
|
||||||
|
#include "action_layer.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "ergodone.h"
|
||||||
|
#include "expander.h"
|
||||||
|
#ifdef DEBUG_MATRIX_SCAN_RATE
|
||||||
|
#include "timer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This constant define not debouncing time in msecs, but amount of matrix
|
||||||
|
* scan loops which should be made to get stable debounced results.
|
||||||
|
*
|
||||||
|
* On Ergodox matrix scan rate is relatively low, because of slow I2C.
|
||||||
|
* Now it's only 317 scans/second, or about 3.15 msec/scan.
|
||||||
|
* According to Cherry specs, debouncing time is 5 msec.
|
||||||
|
*
|
||||||
|
* And so, there is no sense to have DEBOUNCE higher than 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEBOUNCE
|
||||||
|
# define DEBOUNCE 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* matrix state(1:on, 0:off) */
|
||||||
|
static matrix_row_t matrix[MATRIX_ROWS];
|
||||||
|
|
||||||
|
// Debouncing: store for each key the number of scans until it's eligible to
|
||||||
|
// change. When scanning the matrix, ignore any changes in keys that have
|
||||||
|
// already changed in the last DEBOUNCE scans.
|
||||||
|
static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
|
||||||
|
|
||||||
|
static matrix_row_t read_cols(uint8_t row);
|
||||||
|
static void init_cols(void);
|
||||||
|
static void unselect_rows(void);
|
||||||
|
static void select_row(uint8_t row);
|
||||||
|
|
||||||
|
#ifdef DEBUG_MATRIX_SCAN_RATE
|
||||||
|
uint32_t matrix_timer;
|
||||||
|
uint32_t matrix_scan_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void matrix_init_user(void) {}
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void matrix_scan_user(void) {}
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void matrix_init_kb(void) {
|
||||||
|
matrix_init_user();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void matrix_scan_kb(void) {
|
||||||
|
matrix_scan_user();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_rows(void)
|
||||||
|
{
|
||||||
|
return MATRIX_ROWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_cols(void)
|
||||||
|
{
|
||||||
|
return MATRIX_COLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_init(void)
|
||||||
|
{
|
||||||
|
// disable JTAG
|
||||||
|
MCUCR = (1<<JTD);
|
||||||
|
MCUCR = (1<<JTD);
|
||||||
|
|
||||||
|
unselect_rows();
|
||||||
|
init_cols();
|
||||||
|
|
||||||
|
// initialize matrix state: all keys off
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
|
matrix[i] = 0;
|
||||||
|
for (uint8_t j=0; j < MATRIX_COLS; ++j) {
|
||||||
|
debounce_matrix[i * MATRIX_COLS + j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_MATRIX_SCAN_RATE
|
||||||
|
matrix_timer = timer_read32();
|
||||||
|
matrix_scan_count = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
matrix_init_quantum();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_power_up(void) {
|
||||||
|
unselect_rows();
|
||||||
|
init_cols();
|
||||||
|
|
||||||
|
// initialize matrix state: all keys off
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
|
matrix[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_MATRIX_SCAN_RATE
|
||||||
|
matrix_timer = timer_read32();
|
||||||
|
matrix_scan_count = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a matrix_row_t whose bits are set if the corresponding key should be
|
||||||
|
// eligible to change in this scan.
|
||||||
|
matrix_row_t debounce_mask(uint8_t row) {
|
||||||
|
matrix_row_t result = 0;
|
||||||
|
for (uint8_t j=0; j < MATRIX_COLS; ++j) {
|
||||||
|
if (debounce_matrix[row * MATRIX_COLS + j]) {
|
||||||
|
--debounce_matrix[row * MATRIX_COLS + j];
|
||||||
|
} else {
|
||||||
|
result |= (1 << j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report changed keys in the given row. Resets the debounce countdowns
|
||||||
|
// corresponding to each set bit in 'change' to DEBOUNCE.
|
||||||
|
void debounce_report(matrix_row_t change, uint8_t row) {
|
||||||
|
for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
|
||||||
|
if (change & (1 << i)) {
|
||||||
|
debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t matrix_scan(void)
|
||||||
|
{
|
||||||
|
expander_scan();
|
||||||
|
|
||||||
|
#ifdef DEBUG_MATRIX_SCAN_RATE
|
||||||
|
matrix_scan_count++;
|
||||||
|
|
||||||
|
uint32_t timer_now = timer_read32();
|
||||||
|
if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
|
||||||
|
print("matrix scan frequency: ");
|
||||||
|
pdec(matrix_scan_count);
|
||||||
|
print("\n");
|
||||||
|
matrix_print();
|
||||||
|
|
||||||
|
matrix_timer = timer_now;
|
||||||
|
matrix_scan_count = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
select_row(i);
|
||||||
|
wait_us(30); // without this wait read unstable value.
|
||||||
|
matrix_row_t mask = debounce_mask(i);
|
||||||
|
matrix_row_t cols = (read_cols(i) & mask) | (matrix[i] & ~mask);
|
||||||
|
debounce_report(cols ^ matrix[i], i);
|
||||||
|
matrix[i] = cols;
|
||||||
|
|
||||||
|
unselect_rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix_scan_quantum();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Column pin configuration
|
||||||
|
*
|
||||||
|
* Pro Micro: 6 5 4 3 2 1 0
|
||||||
|
* PD3 PD2 PD4 PC6 PD7 PE6 PB4
|
||||||
|
*
|
||||||
|
* Expander: 13 12 11 10 9 8 7
|
||||||
|
*/
|
||||||
|
static void init_cols(void)
|
||||||
|
{
|
||||||
|
// Pro Micro
|
||||||
|
DDRE &= ~(1<<PE6);
|
||||||
|
PORTE |= (1<<PE6);
|
||||||
|
DDRD &= ~(1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7);
|
||||||
|
PORTD |= (1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7);
|
||||||
|
DDRC &= ~(1<<PC6);
|
||||||
|
PORTC |= (1<<PC6);
|
||||||
|
DDRB &= ~(1<<PB4);
|
||||||
|
PORTB |= (1<<PB4);
|
||||||
|
|
||||||
|
// MCP23017
|
||||||
|
expander_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static matrix_row_t read_cols(uint8_t row)
|
||||||
|
{
|
||||||
|
return expander_read_row() |
|
||||||
|
(PIND&(1<<PD3) ? 0 : (1<<6)) |
|
||||||
|
(PIND&(1<<PD2) ? 0 : (1<<5)) |
|
||||||
|
(PIND&(1<<PD4) ? 0 : (1<<4)) |
|
||||||
|
(PINC&(1<<PC6) ? 0 : (1<<3)) |
|
||||||
|
(PIND&(1<<PD7) ? 0 : (1<<2)) |
|
||||||
|
(PINE&(1<<PE6) ? 0 : (1<<1)) |
|
||||||
|
(PINB&(1<<PB4) ? 0 : (1<<0)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Row pin configuration
|
||||||
|
*
|
||||||
|
* Pro Micro: 0 1 2 3 4 5
|
||||||
|
* F4 F5 F6 F7 B1 B2
|
||||||
|
*
|
||||||
|
* Expander: 0 1 2 3 4 5
|
||||||
|
*/
|
||||||
|
static void unselect_rows(void)
|
||||||
|
{
|
||||||
|
// Pro Micro
|
||||||
|
DDRF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7);
|
||||||
|
PORTF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7);
|
||||||
|
DDRB &= ~(1<<PB1 | 1<<PB2);
|
||||||
|
PORTB &= ~(1<<PB1 | 1<<PB2);
|
||||||
|
|
||||||
|
// Expander
|
||||||
|
expander_unselect_rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void select_row(uint8_t row)
|
||||||
|
{
|
||||||
|
// Pro Micro
|
||||||
|
switch (row) {
|
||||||
|
case 0:
|
||||||
|
DDRF |= (1<<PF4);
|
||||||
|
PORTF &= ~(1<<PF4);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
DDRF |= (1<<PF5);
|
||||||
|
PORTF &= ~(1<<PF5);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
DDRF |= (1<<PF6);
|
||||||
|
PORTF &= ~(1<<PF6);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
DDRF |= (1<<PF7);
|
||||||
|
PORTF &= ~(1<<PF7);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
DDRB |= (1<<PB1);
|
||||||
|
PORTB &= ~(1<<PB1);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
DDRB |= (1<<PB2);
|
||||||
|
PORTB &= ~(1<<PB2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
expander_select_row(row);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
|||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# On command line:
|
||||||
|
#
|
||||||
|
# make = Make software.
|
||||||
|
#
|
||||||
|
# make clean = Clean out built project files.
|
||||||
|
#
|
||||||
|
# That's pretty much all you need. To compile, always go make clean,
|
||||||
|
# followed by make.
|
||||||
|
#
|
||||||
|
# For advanced users only:
|
||||||
|
# make teensy = Download the hex file to the device, using teensy_loader_cli.
|
||||||
|
# (must have teensy_loader_cli installed).
|
||||||
|
#
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# # project specific files
|
||||||
|
SRC = \
|
||||||
|
twimaster.c \
|
||||||
|
matrix.c \
|
||||||
|
expander.c \
|
||||||
|
|
||||||
|
# MCU name
|
||||||
|
MCU = atmega32u4
|
||||||
|
|
||||||
|
# Processor frequency.
|
||||||
|
# This will define a symbol, F_CPU, in all source code files equal to the
|
||||||
|
# processor frequency in Hz. You can then use this symbol in your source code to
|
||||||
|
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
||||||
|
# automatically to create a 32-bit value in your source code.
|
||||||
|
#
|
||||||
|
# This will be an integer division of F_USB below, as it is sourced by
|
||||||
|
# F_USB after it has run through any CPU prescalers. Note that this value
|
||||||
|
# does not *change* the processor frequency - it should merely be updated to
|
||||||
|
# reflect the processor speed set externally so that the code can use accurate
|
||||||
|
# software delays.
|
||||||
|
F_CPU = 16000000
|
||||||
|
|
||||||
|
#
|
||||||
|
# LUFA specific
|
||||||
|
#
|
||||||
|
# Target architecture (see library "Board Types" documentation).
|
||||||
|
ARCH = AVR8
|
||||||
|
|
||||||
|
# Input clock frequency.
|
||||||
|
# This will define a symbol, F_USB, in all source code files equal to the
|
||||||
|
# input clock frequency (before any prescaling is performed) in Hz. This value may
|
||||||
|
# differ from F_CPU if prescaling is used on the latter, and is required as the
|
||||||
|
# raw input clock is fed directly to the PLL sections of the AVR for high speed
|
||||||
|
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
|
||||||
|
# at the end, this will be done automatically to create a 32-bit value in your
|
||||||
|
# source code.
|
||||||
|
#
|
||||||
|
# If no clock division is performed on the input clock inside the AVR (via the
|
||||||
|
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
|
||||||
|
F_USB = $(F_CPU)
|
||||||
|
|
||||||
|
# Interrupt driven control endpoint task(+60)
|
||||||
|
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
|
||||||
|
|
||||||
|
|
||||||
|
# Boot Section Size in *bytes*
|
||||||
|
# Teensy halfKay 512
|
||||||
|
# Teensy++ halfKay 1024
|
||||||
|
# Atmel DFU loader 4096
|
||||||
|
# LUFA bootloader 4096
|
||||||
|
# USBaspLoader 2048
|
||||||
|
OPT_DEFS += -DBOOTLOADER_SIZE=4096
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
|
||||||
|
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
|
||||||
|
CONSOLE_ENABLE = no # Console for debug(+400)
|
||||||
|
COMMAND_ENABLE = no # Commands for debug and configuration
|
||||||
|
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
|
||||||
|
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
|
||||||
|
USB_6KRO_ENABLE = no # USB 6key Rollover
|
||||||
|
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
|
||||||
|
KEYMAP_IN_EEPROM_ENABLE = no # External keymap in eeprom
|
||||||
|
KEYMAP_SECTION_ENABLE = no # Fixed address keymap for keymap editor
|
||||||
|
SOFTPWM_LED_ENABLE = no # Enable SoftPWM to drive backlight
|
||||||
|
FADING_LED_ENABLE = no # Enable fading backlight
|
||||||
|
BREATHING_LED_ENABLE = no # Enable breathing backlight
|
||||||
|
LEDMAP_ENABLE = no # Enable LED mapping
|
||||||
|
LEDMAP_IN_EEPROM_ENABLE = no # Read LED mapping from eeprom
|
||||||
|
ONEHAND_ENABLE = no # Disable Onehand
|
||||||
|
RGBLIGHT_ENABLE = no
|
||||||
|
MIDI_ENABLE = no
|
@ -0,0 +1,208 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Title: I2C master library using hardware TWI interface
|
||||||
|
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||||||
|
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
|
||||||
|
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
|
||||||
|
* Target: any AVR device with hardware TWI
|
||||||
|
* Usage: API compatible with I2C Software Library i2cmaster.h
|
||||||
|
**************************************************************************/
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <compat/twi.h>
|
||||||
|
|
||||||
|
#include <i2cmaster.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* define CPU frequency in Mhz here if not defined in Makefile */
|
||||||
|
#ifndef F_CPU
|
||||||
|
#define F_CPU 16000000UL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* I2C clock in Hz */
|
||||||
|
#define SCL_CLOCK 400000L
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Initialization of the I2C bus interface. Need to be called only once
|
||||||
|
*************************************************************************/
|
||||||
|
void i2c_init(void)
|
||||||
|
{
|
||||||
|
/* initialize TWI clock
|
||||||
|
* minimal values in Bit Rate Register (TWBR) and minimal Prescaler
|
||||||
|
* bits in the TWI Status Register should give us maximal possible
|
||||||
|
* I2C bus speed - about 444 kHz
|
||||||
|
*
|
||||||
|
* for more details, see 20.5.2 in ATmega16/32 secification
|
||||||
|
*/
|
||||||
|
|
||||||
|
TWSR = 0; /* no prescaler */
|
||||||
|
TWBR = 10; /* must be >= 10 for stable operation */
|
||||||
|
|
||||||
|
}/* i2c_init */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Issues a start condition and sends address and transfer direction.
|
||||||
|
return 0 = device accessible, 1= failed to access device
|
||||||
|
*************************************************************************/
|
||||||
|
unsigned char i2c_start(unsigned char address)
|
||||||
|
{
|
||||||
|
uint8_t twst;
|
||||||
|
|
||||||
|
// send START condition
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||||||
|
|
||||||
|
// wait until transmission completed
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
|
twst = TW_STATUS & 0xF8;
|
||||||
|
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
|
||||||
|
|
||||||
|
// send device address
|
||||||
|
TWDR = address;
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
|
// wail until transmission completed and ACK/NACK has been received
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
|
twst = TW_STATUS & 0xF8;
|
||||||
|
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}/* i2c_start */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Issues a start condition and sends address and transfer direction.
|
||||||
|
If device is busy, use ack polling to wait until device is ready
|
||||||
|
|
||||||
|
Input: address and transfer direction of I2C device
|
||||||
|
*************************************************************************/
|
||||||
|
void i2c_start_wait(unsigned char address)
|
||||||
|
{
|
||||||
|
uint8_t twst;
|
||||||
|
|
||||||
|
|
||||||
|
while ( 1 )
|
||||||
|
{
|
||||||
|
// send START condition
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||||||
|
|
||||||
|
// wait until transmission completed
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
|
twst = TW_STATUS & 0xF8;
|
||||||
|
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
|
||||||
|
|
||||||
|
// send device address
|
||||||
|
TWDR = address;
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
|
// wail until transmission completed
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
|
twst = TW_STATUS & 0xF8;
|
||||||
|
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
|
||||||
|
{
|
||||||
|
/* device busy, send stop condition to terminate write operation */
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||||
|
|
||||||
|
// wait until stop condition is executed and bus released
|
||||||
|
while(TWCR & (1<<TWSTO));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//if( twst != TW_MT_SLA_ACK) return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}/* i2c_start_wait */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Issues a repeated start condition and sends address and transfer direction
|
||||||
|
|
||||||
|
Input: address and transfer direction of I2C device
|
||||||
|
|
||||||
|
Return: 0 device accessible
|
||||||
|
1 failed to access device
|
||||||
|
*************************************************************************/
|
||||||
|
unsigned char i2c_rep_start(unsigned char address)
|
||||||
|
{
|
||||||
|
return i2c_start( address );
|
||||||
|
|
||||||
|
}/* i2c_rep_start */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Terminates the data transfer and releases the I2C bus
|
||||||
|
*************************************************************************/
|
||||||
|
void i2c_stop(void)
|
||||||
|
{
|
||||||
|
/* send stop condition */
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||||
|
|
||||||
|
// wait until stop condition is executed and bus released
|
||||||
|
while(TWCR & (1<<TWSTO));
|
||||||
|
|
||||||
|
}/* i2c_stop */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Send one byte to I2C device
|
||||||
|
|
||||||
|
Input: byte to be transfered
|
||||||
|
Return: 0 write successful
|
||||||
|
1 write failed
|
||||||
|
*************************************************************************/
|
||||||
|
unsigned char i2c_write( unsigned char data )
|
||||||
|
{
|
||||||
|
uint8_t twst;
|
||||||
|
|
||||||
|
// send data to the previously addressed device
|
||||||
|
TWDR = data;
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
|
// wait until transmission completed
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
// check value of TWI Status Register. Mask prescaler bits
|
||||||
|
twst = TW_STATUS & 0xF8;
|
||||||
|
if( twst != TW_MT_DATA_ACK) return 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}/* i2c_write */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Read one byte from the I2C device, request more data from device
|
||||||
|
|
||||||
|
Return: byte read from I2C device
|
||||||
|
*************************************************************************/
|
||||||
|
unsigned char i2c_readAck(void)
|
||||||
|
{
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
return TWDR;
|
||||||
|
|
||||||
|
}/* i2c_readAck */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Read one byte from the I2C device, read is followed by a stop condition
|
||||||
|
|
||||||
|
Return: byte read from I2C device
|
||||||
|
*************************************************************************/
|
||||||
|
unsigned char i2c_readNak(void)
|
||||||
|
{
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
while(!(TWCR & (1<<TWINT)));
|
||||||
|
|
||||||
|
return TWDR;
|
||||||
|
|
||||||
|
}/* i2c_readNak */
|
Loading…
Reference in new issue