Add i2c slave support to arduino firmware
This commit is contained in:
parent
badc84d99b
commit
73cd5f1cdf
87
src/arch/avr/i2c_slave.c
Normal file
87
src/arch/avr/i2c_slave.c
Normal file
@ -0,0 +1,87 @@
|
||||
// Based on https://github.com/thegouger/avr-i2c-slave
|
||||
|
||||
#include <stdio.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include <board/cpu.h>
|
||||
#include <arch/i2c_slave.h>
|
||||
|
||||
static void (* volatile i2c_slave_new_cb)() = NULL;
|
||||
static void (* volatile i2c_slave_recv_cb)(uint8_t) = NULL;
|
||||
static uint8_t (* volatile i2c_slave_send_cb)() = NULL;
|
||||
|
||||
void i2c_slave_init(uint8_t address, void (*new_cb)(), void (*recv_cb)(uint8_t), uint8_t (*send_cb)()){
|
||||
// ensure correct behavior by stopping before changing callbacks or address
|
||||
i2c_slave_stop();
|
||||
|
||||
// clear interrupts
|
||||
cli();
|
||||
|
||||
// setup callbacks
|
||||
i2c_slave_new_cb = new_cb;
|
||||
i2c_slave_recv_cb = recv_cb;
|
||||
i2c_slave_send_cb = send_cb;
|
||||
// load address into TWI address register
|
||||
TWAR = (address << 1);
|
||||
// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
|
||||
TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
|
||||
|
||||
// set interrupts
|
||||
sei();
|
||||
}
|
||||
|
||||
void i2c_slave_stop(){
|
||||
// clear interrupts
|
||||
cli();
|
||||
|
||||
// clear acknowledge and enable bits
|
||||
TWCR &= ~((1<<TWEA) | (1<<TWEN));
|
||||
// clear address
|
||||
TWAR = 0;
|
||||
// remove callbacks
|
||||
i2c_slave_new_cb = NULL;
|
||||
i2c_slave_recv_cb = NULL;
|
||||
i2c_slave_send_cb = NULL;
|
||||
|
||||
// set interrupts
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR(TWI_vect) {
|
||||
uint8_t status = TW_STATUS;
|
||||
switch(status) {
|
||||
case TW_SR_SLA_ACK:
|
||||
// master has started a new transaction, call the new callback
|
||||
if (i2c_slave_new_cb != NULL) {
|
||||
i2c_slave_new_cb();
|
||||
}
|
||||
TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
|
||||
break;
|
||||
case TW_SR_DATA_ACK:
|
||||
// received data from master, call the receive callback
|
||||
if(i2c_slave_send_cb != NULL){
|
||||
i2c_slave_recv_cb(TWDR);
|
||||
}
|
||||
TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
|
||||
break;
|
||||
case TW_ST_SLA_ACK:
|
||||
case TW_ST_DATA_ACK:
|
||||
// master is requesting data, call the send callback
|
||||
if(i2c_slave_recv_cb != NULL) {
|
||||
TWDR = i2c_slave_send_cb();
|
||||
}
|
||||
TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
|
||||
break;
|
||||
case TW_BUS_ERROR:
|
||||
// some sort of erroneous state, prepare TWI to be readdressed
|
||||
printf("TWI_vect bus error\n");
|
||||
TWCR = 0;
|
||||
TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
|
||||
break;
|
||||
default:
|
||||
TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
|
||||
break;
|
||||
}
|
||||
}
|
7
src/arch/avr/include/arch/i2c_slave.h
Normal file
7
src/arch/avr/include/arch/i2c_slave.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _ARCH_I2C_SLAVE_H
|
||||
#define _ARCH_I2C_SLAVE_H
|
||||
|
||||
void i2c_slave_init(uint8_t address, void (*new_cb)(), void (*recv_cb)(uint8_t), uint8_t (*send_cb)());
|
||||
void i2c_slave_stop();
|
||||
|
||||
#endif // _ARCH_I2C_SLAVE_H
|
@ -6,6 +6,10 @@ uint8_t smbus_read(uint8_t address, uint8_t command, uint16_t * data) {
|
||||
return i2c_get(address, command, (uint8_t *)data, 2);
|
||||
}
|
||||
|
||||
uint8_t smbus_write(uint8_t address, uint8_t command, uint16_t data) {
|
||||
return i2c_set(address, command, (uint8_t *)&data, 2);
|
||||
}
|
||||
|
||||
void battery_debug(void) {
|
||||
uint16_t data = 0;
|
||||
uint8_t err = 0;
|
||||
@ -15,9 +19,9 @@ void battery_debug(void) {
|
||||
err = smbus_read(A, V, &data); \
|
||||
if (err) { \
|
||||
printf("ERROR %02X\n", err); \
|
||||
return; \
|
||||
} else { \
|
||||
printf("%04X\n", data); \
|
||||
} \
|
||||
printf("%04X\n", data); \
|
||||
}
|
||||
|
||||
printf("Battery:\n");
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef _BOARD_I2C_H
|
||||
#define _BOARD_I2C_H
|
||||
|
||||
#include <arch/i2c.h>
|
||||
|
||||
void i2c_init(unsigned long baud);
|
||||
|
||||
#endif // _BOARD_I2C_H
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arch/gpio.h>
|
||||
#include <arch/i2c_slave.h>
|
||||
#include <arch/uart.h>
|
||||
#include <board/battery.h>
|
||||
#include <board/i2c.h>
|
||||
@ -10,6 +11,16 @@ void init(void) {
|
||||
i2c_init(50000);
|
||||
}
|
||||
|
||||
static void i2c_slave_new() {}
|
||||
|
||||
static void i2c_slave_recv(uint8_t data) {
|
||||
printf("%c", data);
|
||||
}
|
||||
|
||||
static uint8_t i2c_slave_send() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Gpio LED = GPIO(B, 7);
|
||||
|
||||
int main(void) {
|
||||
@ -22,7 +33,9 @@ int main(void) {
|
||||
battery_debug();
|
||||
|
||||
for (;;) {
|
||||
i2c_slave_init(0x76, i2c_slave_new, i2c_slave_recv, i2c_slave_send);
|
||||
int c = getchar();
|
||||
i2c_slave_stop();
|
||||
if (c == '\r') {
|
||||
putchar('\n');
|
||||
battery_debug();
|
||||
|
Loading…
x
Reference in New Issue
Block a user