diff --git a/radio/nrf24L01/nrf-ftdi-ring.c b/radio/nrf24L01/nrf-ftdi-ring.c new file mode 100644 index 0000000000000000000000000000000000000000..f484375091d54571fd164ea1cac7e858dd1ed293 --- /dev/null +++ b/radio/nrf24L01/nrf-ftdi-ring.c @@ -0,0 +1,398 @@ +// +// xmega spi for LIS3MDL, 3 axis magnetometer with Xmega 8E5 +// sec, 2016 +#ifndef F_CPU +#define F_CPU 32000000UL +#endif + +#include "serial.h" +#include <avr/io.h> +#include <util/delay.h> +#include <avr/pgmspace.h> +#include <avr/interrupt.h> + +#define SS_BM PIN4_bm +#define CE_BM PIN0_bm +#define IRQ_BM PIN2_bm + +//NRF24L01 registers +//https://www.nordicsemi.com/eng/content/download/2726/34069/file/nrf24L01P_Product_Specification_1_0.pdf +//Every new command must be started by a high to low transition on CSN. +const uint8_t CONFIG = 0x00; +const uint8_t EN_AA = 0x01; +const uint8_t EN_RXADDR = 0x02; +const uint8_t SETUP_AW = 0x03; +const uint8_t SETUP_RETR = 0x04; +const uint8_t RF_CH = 0x05; +const uint8_t RF_SETUP = 0x06; +const uint8_t STATUS = 0x07; +const uint8_t OBSERVE_TX = 0x08; +const uint8_t RPD = 0x09; +const uint8_t RX_ADDR_P0 = 0x0A; +const uint8_t RX_ADDR_P1 = 0x0B; +const uint8_t RX_ADDR_P2 = 0x0C; +const uint8_t RX_ADDR_P3 = 0x0D; +const uint8_t RX_ADDR_P4 = 0x0E; +const uint8_t RX_ADDR_P5 = 0x0F; +const uint8_t TX_ADDR = 0x10; +const uint8_t RX_PW_P0 = 0x11; +const uint8_t RX_PW_P1 = 0x12; +const uint8_t RX_PW_P2 = 0x13; +const uint8_t RX_PW_P3 = 0x14; +const uint8_t RX_PW_P4 = 0x15; +const uint8_t RX_PW_P5 = 0x16; +const uint8_t FIFO_STATUS = 0x17; +const uint8_t DYNPD = 0x1C; +const uint8_t FEATURE = 0x1D; + +const uint8_t PWR_UP = 1 << 1; +const uint8_t PRIM_RX = 1 << 0; +const uint8_t R_REGISTER = 0; +const uint8_t W_REGISTER = 1<<5; +const uint8_t R_RX_PAYLOAD = (1<<6) | (1<<5) | 1; +const uint8_t W_TX_PAYLOAD = (1<<7) | (1<<5); +const uint8_t FLUSH_TX = (1<<7) | (1<<6) | (1<<5) | 1; +const uint8_t FLUSH_RX = (1<<7) | (1<<6) | (1<<5) | (1<<1); +const uint8_t MAX_RT = 1<<4; +const uint8_t TX_DS = 1<<5; //tx data sent interrupt +const uint8_t RX_DR = 1<<6; //rx data ready interrupt + + +uint8_t read_register(uint8_t reg){ + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); //give time after ss low + SPIC.DATA = R_REGISTER | reg; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + uint8_t temp = SPIC.DATA; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time after ss high + return temp; +} + + + +USART_data_t USART_data; + +uint8_t token = 0; //token to pass +uint8_t tempval = 0; + +void check_registers(){ + //enter standby so we can write to configuration register. + PORTC.OUTCLR = CE_BM; + _delay_us(10); + + //read registers for debug + PORTC.OUTCLR = SS_BM; //SS low + _delay_us(10); + SPIC.DATA = R_REGISTER | EN_AA; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + uint8_t status = SPIC.DATA; + SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; //read + uint8_t en_aa = SPIC.DATA; + PORTC.OUTSET = SS_BM; //SS high + _delay_us(10); + + PORTC.OUTCLR = SS_BM; //SS low + _delay_us(10); + SPIC.DATA = R_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; //read + uint8_t config = SPIC.DATA; + PORTC.OUTSET = SS_BM; //SS high + _delay_us(10); + + PORTC.OUTCLR = SS_BM; //SS low + _delay_us(10); + SPIC.DATA = R_REGISTER | SETUP_RETR; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; //read + uint8_t setup_retr = SPIC.DATA; + PORTC.OUTSET = SS_BM; //SS high + _delay_us(10); + + usart_send_byte(&USART_data,status); + usart_send_byte(&USART_data,config); + usart_send_byte(&USART_data,en_aa); + usart_send_byte(&USART_data,setup_retr); + usart_send_byte(&USART_data,token); + usart_send_byte(&USART_data,10); + + //interrupts + /*if (!(PORTC.IN & IRQ_BM)){ + usart_send_byte(&USART_data,1); + } + //clear interrupt on MAX_RT + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA |= MAX_RT; while(!(SPIC.STATUS & SPI_IF_bm)) {}; //write 1 to MAX_RT bit + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + //interrupts + if (!(PORTC.IN & IRQ_BM)){ + usart_send_byte(&USART_data,2); + }*/ +} + +// nRF24L01+ must be in a standby or power down mode before writing to the configuration registers. + +//overview +// - turn off autoretransmit +// - MAX_RT interrupts on IRQ +// - set interrupt service routine on rising edge of IRQ (RX_DR) +// - set interrupt service routing on USART RX +// - enter RX mode PRIM_RX = 1 (SPI transaction), CE = 1 +// - When IRQ interupt, +// - enter standby (CE=0) +// - read payload (SPI transaction) +// - process data and put result in TX fifo +// - enter TX (PRIM_RX=0, CE=1 for more than 10 us) (130us) +// - clear IRQ by writing 1 to STATUS register RX_DR bit. (SPI transaction) +// - set CE=0 so we return to Standby when finished transmitting +// - set PRIM_RX=1 (SPI transaction). can we only do this from standby? (130us) +// - When USART interrupt, +// - enter standby (CE=0) +// - put token in TX fifo +// - enter TX (PRIM_RX=0, CE=1 for more than 10 us) +// - set CE=0 so we return to Standby when finished transmitting +// - set PRIM_RX=1 (SPI transaction) to enter RX can we only do this from standby? (130us) + +//experiments +// RF_SETUP, RF_DR_LOW, RF_DR_HIGH. Default RF data rate is 250kbps ( 4 us per byte ). +// It can also be 1 Mbps (1 us per byte) and 2 Mbps (.5 us per byte) +// increase SPI rate. right now its running at clkper/128 = sysclk/128 = 250 kHz (4 us per byte) + + +void rx_from_standby(){ + //enter standby so we can write to configuration register. + PORTC.OUTCLR = CE_BM; + _delay_us(10); + + //enter RX mode: set PRIM_RX = 1 + tempval = read_register(CONFIG); + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval | PRIM_RX; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + //set CE for at least 10 us + PORTC.OUTSET = CE_BM; + _delay_us(10); + + //wait for pll to settle + _delay_us(130); +} + +void setup(){ + // set up clock + OSC.CTRL = OSC_RC32MEN_bm; // enable 32MHz clock + while (!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait for clock to be ready + CCP = CCP_IOREG_gc; // enable protected register change + CLK.CTRL = CLK_SCLKSEL_RC32M_gc; // switch to 32MHz clock + + //set up usart + PORTD.DIRSET = PIN3_bm; //TXD0 + PORTD.DIRCLR = PIN2_bm; //RXD0 + USART_InterruptDriver_Initialize(&USART_data, &USARTD0, USART_DREINTLVL_LO_gc); + USART_Format_Set(USART_data.usart, USART_CHSIZE_8BIT_gc, + USART_PMODE_DISABLED_gc, 0); + USART_RxdInterruptLevel_Set(USART_data.usart, USART_RXCINTLVL_LO_gc); + //take f_sysclk/(BSEL+1) ~= f_baud*16 with zero scale. See manual or spreadsheet for scale defs + USART_Baudrate_Set(&USARTD0, 123 , -4); //230400 baud with .08% error + USART_Rx_Enable(USART_data.usart); + USART_Tx_Enable(USART_data.usart); + //enable interrupts + PMIC.CTRL |= PMIC_LOLVLEX_bm; + + + PORTC.DIRSET = SS_BM; //set up SS pin on PC4 + PORTC.PIN4CTRL = PORT_OPC_WIREDANDPULL_gc; //wired AND and pull-up on SS + PORTC.PIN2CTRL = PORT_OPC_PULLUP_gc; //pull-up on IRQ + PORTC.DIRSET = CE_BM; //set up CE pin on PC0 + //set up spic.ctrl + SPIC.CTRL = SPI_PRESCALER_DIV128_gc | /* SPI prescaler. */ + (0 ? SPI_CLK2X_bm : 0) | /* SPI Clock double. */ + SPI_ENABLE_bm | /* Enable SPI module. */ + SPI_MASTER_bm | /* SPI master. */ + SPI_MODE_0_gc; //bits driven at falling edge, sampled at rising edge + SPIC.INTCTRL = SPI_INTLVL_OFF_gc; + PORTC.DIRSET = PIN5_bm | PIN7_bm; //mosi and sck as outputs + PORTC.OUTSET = SS_BM; //SS high + + _delay_ms(5); //warm up + + + //turn off auto-retransmit + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | SETUP_RETR; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0 ; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + //turn off disable auto-acknowledge + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | EN_AA; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0 ; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + //set the PWR_UP bit in the CONFIG register to 1 to enter standby mode + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = PWR_UP; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + //set up data pipe 0 + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | EN_RXADDR; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 1; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + //set data pipe 0 payload length to 1 + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | RX_PW_P0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 1; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + //flush tx + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = FLUSH_TX; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + //flush rx + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = FLUSH_TX; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + // and mask MAX_RT interrupts on IRQ + tempval = read_register(CONFIG); + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval | MAX_RT; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + //clear all interrupts + tempval = read_register(STATUS); + PORTC.OUTCLR = SS_BM; //SS low + SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval | MAX_RT | RX_DR | TX_DS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); //give time to start up + + // + + sei(); + + rx_from_standby(); + +} + + +// NOTE: we can't do SPIC.DATA &= or |= thing because SPIC.DATA will hold STATUS!!! + + +void send_token(){ + //transition from RX to standby1 (CE=0) + PORTC.OUTCLR = CE_BM; + _delay_us(10); + + //put token in tx fifo + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = W_TX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = token; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + check_registers(); + + tempval = read_register(CONFIG); + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = W_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval & (~PRIM_RX); while(!(SPIC.STATUS & SPI_IF_bm)) {}; //make sure PRIM_RX is low + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + check_registers(); + + //pulse CE for at least 10 us + PORTC.OUTSET = CE_BM; _delay_us(15); PORTC.OUTCLR = CE_BM; + + //wait for pll to settle + _delay_us(130); + + //wait until transmit complete + usart_send_byte(&USART_data,68); usart_send_byte(&USART_data,10); //for debug on usart + while( PORTC.IN & IRQ_BM ){} + usart_send_byte(&USART_data,69); usart_send_byte(&USART_data,10); //for debug on usart + + //clear IRQ -- need to be in standby. + tempval = read_register(STATUS); + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval | TX_DS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + rx_from_standby(); //return to RX mode +} + +void read_token(){ + check_registers(); + //get token from rx fifo + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = R_RX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + token = SPIC.DATA; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + + //transition from RX to standby1 (CE=0) + PORTC.OUTCLR = CE_BM; + _delay_us(10); + + //clear IRQ + tempval = read_register(STATUS); + PORTC.OUTCLR = SS_BM; //SS low + _delay_ms(1); + SPIC.DATA = W_REGISTER | STATUS; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + SPIC.DATA = tempval | RX_DR; while(!(SPIC.STATUS & SPI_IF_bm)) {}; + PORTC.OUTSET = SS_BM; //SS high + _delay_ms(1); + usart_send_byte(&USART_data,255); usart_send_byte(&USART_data,10); //for debug on usart + check_registers(); +} + +int main(void) { + setup(); + while(1){ + //should be in rx mode here. + if ( !(PORTC.IN & IRQ_BM)){ + usart_send_byte(&USART_data,70); usart_send_byte(&USART_data,10); + read_token(); //in standby + token = 1-token; //transform token + send_token(); //in rx + usart_send_byte(&USART_data,66); usart_send_byte(&USART_data,10); //for debug on usart + } + + //when we get signal from usart, send a token on nrf + if (USART_RXBufferData_Available(&USART_data)) { + usart_send_byte(&USART_data,64); usart_send_byte(&USART_data,10); //for debug on usart + USART_RXBuffer_GetByte(&USART_data); //clear usart buffer so we only fire once. + check_registers(); + send_token(); //in rx + usart_send_byte(&USART_data,65); usart_send_byte(&USART_data,10); //for debug on usart + } + _delay_ms(1000); + } +} + + +ISR(USARTD0_RXC_vect){USART_RXComplete(&USART_data);} +ISR(USARTD0_DRE_vect){USART_DataRegEmpty(&USART_data);} diff --git a/radio/nrf24L01/nrf-ftdi-ring.make b/radio/nrf24L01/nrf-ftdi-ring.make new file mode 100644 index 0000000000000000000000000000000000000000..453d446ab4681c82bb7a043e7190ba1f620aef7e --- /dev/null +++ b/radio/nrf24L01/nrf-ftdi-ring.make @@ -0,0 +1,19 @@ +PROJECT=nrf-ftdi-ring +SOURCES=$(PROJECT).c +MMCU=atxmega8e5 +F_CPU = 32000000 +TARGET = x8e5 +PROGRAMMER= atmelice_pdi + +CFLAGS=-mmcu=$(MMCU) -Wall -Os -DF_CPU=$(F_CPU) + +$(PROJECT).hex: $(PROJECT).out + avr-objcopy -O ihex $(PROJECT).out $(PROJECT).c.hex;\ + avr-size --mcu=$(MMCU) --format=avr $(PROJECT).out + +$(PROJECT).out: $(SOURCES) + avr-gcc $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES) + +program: $(PROJECT).hex + avrdude -p $(TARGET) -c $(PROGRAMMER) -U flash:w:$(PROJECT).c.hex + diff --git a/radio/nrf24L01/serial-monitor.py b/radio/nrf24L01/serial-monitor.py new file mode 100644 index 0000000000000000000000000000000000000000..54bfb554915a54b599bf57f836cd6a9ab04e678e --- /dev/null +++ b/radio/nrf24L01/serial-monitor.py @@ -0,0 +1,23 @@ +import serial,sys + +serial_ports = ["/dev/tty.usbserial-FTFMIM12", "/dev/tty.usbserial-FT9L39VL"] + +ser = serial.Serial(serial_ports[int(sys.argv[1])], 230400) +print "connecting" +labels = ['status','config','en_aa','setup_retr','token'] +while True: + try: + print "writing to usart" + ser.write([0]) + bytes = map(ord,ser.readline().strip('\n')) + #print "read: ",bytes + print bytes + print "Registers:" + for l,b in zip(labels,bytes): + print '\t',l,format(b, '08b') + #if len(labels) != len(bytes): + # print bytes[len(labels):] + except(KeyboardInterrupt): + break +print "Quitting" +ser.close() \ No newline at end of file diff --git a/radio/nrf24L01/serial.h b/radio/nrf24L01/serial.h new file mode 100644 index 0000000000000000000000000000000000000000..4d7312a5ca4cbc6b7815e702b2d655cff1ebd21a --- /dev/null +++ b/radio/nrf24L01/serial.h @@ -0,0 +1,227 @@ +#include <avr/io.h> +#include <util/delay.h> +#include <avr/pgmspace.h> + +#define output(directions,pin) (directions |= pin) // set port direction for output +#define set(port,pin) (port |= pin) // set port pin +#define clear(port,pin) (port &= (~pin)) // clear port pin +#define pin_test(pins,pin) (pins & pin) // test for port pin +#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set + +/* USART buffer defines. */ +/* \brief Receive buffer size: 2,4,8,16,32,64,128 or 256 bytes. */ +#define USART_RX_BUFFER_SIZE 128 +/* \brief Transmit buffer size: 2,4,8,16,32,64,128 or 256 bytes */ +#define USART_TX_BUFFER_SIZE 128 +/* \brief Receive buffer mask. */ +#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 ) +/* \brief Transmit buffer mask. */ +#define USART_TX_BUFFER_MASK ( USART_TX_BUFFER_SIZE - 1 ) + +#if ( USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +/* \brief USART transmit and receive ring buffer. */ +typedef struct USART_Buffer +{ + /* \brief Receive buffer. */ + volatile uint8_t RX[USART_RX_BUFFER_SIZE]; + /* \brief Transmit buffer. */ + volatile uint8_t TX[USART_TX_BUFFER_SIZE]; + /* \brief Receive buffer head. */ + volatile uint8_t RX_Head; + /* \brief Receive buffer tail. */ + volatile uint8_t RX_Tail; + /* \brief Transmit buffer head. */ + volatile uint8_t TX_Head; + /* \brief Transmit buffer tail. */ + volatile uint8_t TX_Tail; +} USART_Buffer_t; + + +/*! \brief Struct used when interrupt driven driver is used. +* +* Struct containing pointer to a usart, a buffer and a location to store Data +* register interrupt level temporary. +*/ +typedef struct Usart_and_buffer +{ + /* \brief Pointer to USART module to use. */ + USART_t * usart; + /* \brief Data register empty interrupt level. */ + USART_DREINTLVL_t dreIntLevel; + /* \brief Data buffer. */ + USART_Buffer_t buffer; +} USART_data_t; + +#define USART_RxdInterruptLevel_Set(_usart, _rxdIntLevel) \ + ((_usart)->CTRLA = ((_usart)->CTRLA & ~USART_RXCINTLVL_gm) | _rxdIntLevel) +#define USART_Format_Set(_usart, _charSize, _parityMode, _twoStopBits) \ + (_usart)->CTRLC = (uint8_t) _charSize | _parityMode | \ + (_twoStopBits ? USART_SBMODE_bm : 0) +#define USART_Baudrate_Set(_usart, _bselValue, _bScaleFactor) \ + (_usart)->BAUDCTRLA =(uint8_t)_bselValue; \ + (_usart)->BAUDCTRLB =(_bScaleFactor << USART_BSCALE0_bp)|(_bselValue >> 8) +#define USART_Rx_Enable(_usart) ((_usart)->CTRLB |= USART_RXEN_bm) +#define USART_Rx_Disable(_usart) ((_usart)->CTRLB &= ~USART_RXEN_bm) +#define USART_Tx_Enable(_usart) ((_usart)->CTRLB |= USART_TXEN_bm) +#define USART_Tx_Disable(_usart) ((_usart)->CTRLB &= ~USART_TXEN_bm) + + + +_Bool USART_TXBuffer_FreeSpace(USART_data_t * usart_data) +{ + /* Make copies to make sure that volatile access is specified. */ + uint8_t tempHead = (usart_data->buffer.TX_Head + 1) & USART_TX_BUFFER_MASK; + uint8_t tempTail = usart_data->buffer.TX_Tail; + + /* There are data left in the buffer unless Head and Tail are equal. */ + return (tempHead != tempTail); +} +_Bool USART_TXBuffer_PutByte(USART_data_t * usart_data, uint8_t data) +{ + uint8_t tempCTRLA; + uint8_t tempTX_Head; + _Bool TXBuffer_FreeSpace; + USART_Buffer_t * TXbufPtr; + + TXbufPtr = &usart_data->buffer; + TXBuffer_FreeSpace = USART_TXBuffer_FreeSpace(usart_data); + + + if(TXBuffer_FreeSpace) + { + tempTX_Head = TXbufPtr->TX_Head; + TXbufPtr->TX[tempTX_Head]= data; + /* Advance buffer head. */ + TXbufPtr->TX_Head = (tempTX_Head + 1) & USART_TX_BUFFER_MASK; + + /* Enable DRE interrupt. */ + tempCTRLA = usart_data->usart->CTRLA; + tempCTRLA = (tempCTRLA & ~USART_DREINTLVL_gm) | usart_data->dreIntLevel; + usart_data->usart->CTRLA = tempCTRLA; + } + return TXBuffer_FreeSpace; +} +_Bool USART_RXBufferData_Available(USART_data_t * usart_data) +{ + /* Make copies to make sure that volatile access is specified. */ + uint8_t tempHead = usart_data->buffer.RX_Head; + uint8_t tempTail = usart_data->buffer.RX_Tail; + + /* There are data left in the buffer unless Head and Tail are equal. */ + return (tempHead != tempTail); +} +uint8_t USART_RXBuffer_GetByte(USART_data_t * usart_data) +{ + USART_Buffer_t * bufPtr; + uint8_t ans; + bufPtr = &usart_data->buffer; + ans = (bufPtr->RX[bufPtr->RX_Tail]); + + /* Advance buffer tail. */ + bufPtr->RX_Tail = (bufPtr->RX_Tail + 1) & USART_RX_BUFFER_MASK; + return ans; +} +_Bool USART_RXComplete(USART_data_t * usart_data) +{ + USART_Buffer_t * bufPtr; + _Bool ans; + + bufPtr = &usart_data->buffer; + /* Advance buffer head. */ + uint8_t tempRX_Head = (bufPtr->RX_Head + 1) & USART_RX_BUFFER_MASK; + + /* Check for overflow. */ + uint8_t tempRX_Tail = bufPtr->RX_Tail; + uint8_t data = usart_data->usart->DATA; + + if (tempRX_Head == tempRX_Tail) { + ans = 0; + }else{ + ans = 1; + usart_data->buffer.RX[usart_data->buffer.RX_Head] = data; + usart_data->buffer.RX_Head = tempRX_Head; + } + return ans; +} +void USART_DataRegEmpty(USART_data_t * usart_data) +{ + USART_Buffer_t * bufPtr; + bufPtr = &usart_data->buffer; + + /* Check if all data is transmitted. */ + uint8_t tempTX_Tail = usart_data->buffer.TX_Tail; + if (bufPtr->TX_Head == tempTX_Tail){ + /* Disable DRE interrupts. */ + uint8_t tempCTRLA = usart_data->usart->CTRLA; + tempCTRLA = (tempCTRLA & ~USART_DREINTLVL_gm) | USART_DREINTLVL_OFF_gc; + usart_data->usart->CTRLA = tempCTRLA; + + }else{ + /* Start transmitting. */ + uint8_t data = bufPtr->TX[usart_data->buffer.TX_Tail]; + usart_data->usart->DATA = data; + + /* Advance buffer tail. */ + bufPtr->TX_Tail = (bufPtr->TX_Tail + 1) & USART_TX_BUFFER_MASK; + } +} +void USART_InterruptDriver_Initialize(USART_data_t * usart_data, + USART_t * usart, + USART_DREINTLVL_t dreIntLevel) +{ + usart_data->usart = usart; + usart_data->dreIntLevel = dreIntLevel; + + usart_data->buffer.RX_Tail = 0; + usart_data->buffer.RX_Head = 0; + usart_data->buffer.TX_Tail = 0; + usart_data->buffer.TX_Head = 0; +} +void USART_InterruptDriver_DreInterruptLevel_Set(USART_data_t * usart_data, + USART_DREINTLVL_t dreIntLevel) +{ + usart_data->dreIntLevel = dreIntLevel; +} + +void usart_send_byte(USART_data_t * usart_data, char msg){ + while(!USART_TXBuffer_FreeSpace(usart_data)){} + USART_TXBuffer_PutByte(usart_data,msg); +} +void usart_send_uint32(USART_data_t * usart_data, uint32_t n){ + unsigned char * nn = (unsigned char *)&n; + usart_send_byte(usart_data, nn[0] ); + usart_send_byte(usart_data, nn[1] ); + usart_send_byte(usart_data, nn[2] ); + usart_send_byte(usart_data, nn[3] ); +} +void usart_send_int32(USART_data_t * usart_data, int32_t n){ + unsigned char * nn = ( unsigned char *)&n; + usart_send_byte(usart_data, nn[0] ); + usart_send_byte(usart_data, nn[1] ); + usart_send_byte(usart_data, nn[2] ); + usart_send_byte(usart_data, nn[3] ); +} +uint32_t parse_uint32(char* b){return *(uint32_t *) b;} +int32_t parse_int32(char* b){return *(int32_t *) b;} +uint16_t parse_uint16(char* b){return *(uint16_t *) b;} + + +/* +void usart_write_buffer(char* buffer){ + //write \n terminated buffer over usart + int j=0; + do{ + usart_send_byte( buffer[j] ); + j++; + } while( j < PACKET_SIZE); + //} while( buffer[j-1] != 10); +} +*/ + +