Functioning I2C slave data receive

The slave now receives and prints data successfully.
This commit is contained in:
Sebastian H. Gabrielli 2024-03-20 13:00:40 +01:00
parent e1c607514b
commit 4e0b810346
4 changed files with 67 additions and 9 deletions

View File

@ -1,6 +1,15 @@
#include "i2c.h" #include "i2c.h"
// Heavily inspired by: https://github.com/microchip-pic-avr-examples/avr128db48-bare-metal-twi-mplab/blob/master/twi-client.X/peripherals/TWI/TWI_client.c
void init_i2c(void) { void init_i2c(void) {
// Pin setup
PORTA.DIRSET = PIN2_bm | PIN3_bm;
PORTA.PINCTRLUPD = PIN2_bm | PIN3_bm;
// Enable operating in debug
TWI0.DBGCTRL = TWI_DBGRUN_bm;
// Initialize the control A register // Initialize the control A register
TWI0.CTRLA = TWI_INPUTLVL_I2C_gc // I2C voltage transition level TWI0.CTRLA = TWI_INPUTLVL_I2C_gc // I2C voltage transition level
| TWI_SDASETUP_4CYC_gc // Four clock cycles setup time | TWI_SDASETUP_4CYC_gc // Four clock cycles setup time
@ -13,20 +22,60 @@ void init_i2c(void) {
// Enable acting as a slave // Enable acting as a slave
TWI0.SCTRLA = TWI_DIEN_bm // Enable data interrupt TWI0.SCTRLA = TWI_DIEN_bm // Enable data interrupt
| TWI_APIEN_bm // Enable more interrupts
| TWI_PIEN_bm // Enable stop flag interrupt | TWI_PIEN_bm // Enable stop flag interrupt
| TWI_SMEN_bm // Enable smart mode | PIN2_bm // Respond to all TWI addresses
| TWI_ENABLE_bm // Enable acting as a slave | TWI_ENABLE_bm // Enable acting as a slave
; ;
} }
// TODO: Figure out which interrupt does what // TODO: Figure out which interrupt does what
// Interrupt vector void i2c_write_handler(uint8_t data) {
ISR(TWI0_TWIS_vect) { printf("%u\n", data);
asm('nop');
} }
// Interrupt vector void i2c_read_handler() {
ISR(TWI0_TWIM_vect) { printf("Master wanted to read.\n");
asm('nop'); }
void i2c_stop_handler() {
printf("Stop, I guess\n");
}
// Address received
ISR(TWI0_TWIS_vect) {
// Check for the data interrupt flag
if (TWI0.SSTATUS & TWI_DIF_bm) {
uint8_t data = 0;
if ( ((TWI0.SSTATUS & TWI_DIR_bm) >> TWI_DIR_bp) == 0 ) {
// Data write Master -> Slave
data = TWI0.SDATA;
// Send the data to the write handler
i2c_write_handler(data);
} else {
// Data read Master <- Slave
i2c_read_handler();
data = TWI0.SDATA;
}
// Acknowledge having received
TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc;
}
// Check for address match or STOP
if (TWI0.SSTATUS & TWI_APIF_bm) {
if (TWI0.SSTATUS & TWI_AP_ADR_gc) {
// Address match, just send ack
TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc;
} else {
// STOP condition received
i2c_stop_handler();
// Send ACK
TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc;
}
}
} }

View File

@ -15,6 +15,8 @@ extern "C" {
// Include the IO for I2C // Include the IO for I2C
#include <avr/io.h> #include <avr/io.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include "uart.h"
#include <util/twi.h>
// Initialize the I2C bus // Initialize the I2C bus
void init_i2c(void); void init_i2c(void);

View File

@ -10,14 +10,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "uart.h" #include "uart.h"
#include "i2c.h"
#include <util/delay.h> #include <util/delay.h>
int main() { int main() {
init_uart((uint16_t)9600); init_uart((uint16_t)9600);
init_i2c();
stdout = &USART_stream; stdout = &USART_stream;
sei();
while (1) { while (1) {
printf("Hello, world!\n"); printf("\n");
_delay_ms(500); _delay_ms(500);
} }
} }

View File

@ -171,6 +171,9 @@
<property key="user-pack-device-support" value=""/> <property key="user-pack-device-support" value=""/>
<property key="wpo-lto" value="false"/> <property key="wpo-lto" value="false"/>
</XC8-config-global> </XC8-config-global>
<nEdbgTool>
<property key="debugoptions.useswbreakpoints" value="true"/>
</nEdbgTool>
</conf> </conf>
</confs> </confs>
</configurationDescriptor> </configurationDescriptor>