Hi all,
The setup that I am aiming for has a number of nodes, which will send the IMU data to a central base station. The communication is achieved using a bunch of nRF24L01+ modules.
So far I have been able to transmit and receive the data from one node to the base station. The problem starts when I want to swap the roles of the node and the base station so that I can transmit and receive the data bi-directionally.
Initially, the base station (configured as TX) sends an 8-byte data to the node (configured as RX). After checking the received data, the node (configured as TX) sends back the IMU data to the base station (configured as RX).
Somehow, after the node receives the data from the base station, it is never able to send the IMU data back to the base station. The TX is done with polling and the RX is done with interrupts.
Can anyone of you point me in the right direction? Thanks!
Additional info:
The nRF (module from Sparkfun) is interfaced with Atmega32U4. IDE is Atmel Studio v7 in Windows platform.
Base station code:
/* * Base_Station.c * * Created: 21-Nov-18 6:18:12 PM * Author : Frederic Philips */ #include <avr/io.h> #include <avr/sfr_defs.h> #include <stdint.h> #include <stdlib.h> #define F_CPU 16000000UL //16 MHz frequency #define BAUD 57600 #include <util/setbaud.h> #include <util/delay.h> #include <avr/interrupt.h> #include "nrf.h" #define MOSI 2 #define MISO 3 #define SCLK 1 #define CSN 0 #define CE 4 #define PAYLOAD_LEN 8 uint8_t BS_payload_TX[PAYLOAD_LEN] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; uint8_t BS_payload_RX[PAYLOAD_LEN]; //0 - TX; 1 - RX volatile uint8_t mode = 0; void nRF_TX_mode(void); void nRF_RX_mode(void); void Flush_tx(void); void Flush_rx(void); void reset(void); void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len); uint8_t nrf24_getStatus(void); uint8_t nrf24_isSending(void); /************************************************************************************ ** AVR_Init function: ** - Start-up delay ** - Initializes the I/O peripherals *************************************************************************************/ void AVR_Init(void) { _delay_ms(750); //Short pause after BNO055 Power-On Reset(Mandatory) DDRD |= _BV(1); //Set TX as output DDRD &= ~(_BV(0)); //Set RX as input } /************************************************************************************ ** USART Reference: ** - ATmega32U4 Datasheet - Rev. CORP072610(Pg.186) ** - AVR Microcontroller and Embedded Systems - Mazidi(Pg.395) ** - Embedded C Programming and the Atmel AVR - Barnett(Pg.132) ************************************************************************************* ** To initialize the UART, the following steps are to be followed: ** - Set the Baud rate(use <util/setbaud.h>, which depends on the macros F_CPU & BAUD) ** - Disable double speed(2x) mode ** - Set the no. of data bits(8/9 bits), stop bit(1/2) and parity bit(None/Odd/Even) ** - Set the USART mode(Synchronous/Asynchronous/Asynchronous 2x) ** - Enable Receiver & Transmitter(Set RXEN & TXEN bits in UCSRB register) *************************************************************************************/ void UART_Init(void) { DDRD |= _BV(1); //Set TX as output DDRD &= ~(_BV(0)); //Set RX as input //Set the BAUD rate(Ref. ATmega32U4 Datasheet Pg.189, Table 18-1) //To hard-code the Baud rate, Ref. Tables 18-9 to 18-12 in Pgs. 210 - 213 UBRR1 = ((F_CPU / (16UL * BAUD)) - 1); //Disables 2x speed UCSR1A &= ~(_BV(U2X1)); //Enable 8-bit character size, one stop-bit, no parity & asynchronous mode UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10); //Enable Transmitter & Receiver UCSR1B |= _BV(TXEN1) | _BV(RXEN1); } /************************************************************************************ ** UART_Tx function: ** - Transmits the ADC data via the USB Serial ** - The data is received & displayed in a Hyperterminal *************************************************************************************/ void UART_Tx(unsigned char data) { loop_until_bit_is_set(UCSR1A, UDRE1); //Wait until buffer is empty UDR1 = data; //Send data } void Init_SPI() { //Set the output pin(s) for SPI DDRB |= _BV(CE); //CE DDRB |= _BV(CSN); //CSN DDRB |= _BV(MOSI); //MOSI DDRB |= _BV(SCLK); //SCLK //Set the input pin(s) for SPI DDRB &= ~_BV(MISO); //MISO SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0)); //Enable SPI as master SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); //Set clock rate but not too important PORTB |= _BV(CSN); //CSN high PORTB &= ~_BV(CE); //CE low } unsigned char spi_tranceiver(unsigned char data) { // Load data into the buffer SPDR = data; //Wait until transmission complete while(!(SPSR & (1 << SPIF))); //Return received data return(SPDR); } unsigned char Read_Byte(unsigned char reg) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(R_REGISTER + reg); _delay_us(10); reg = spi_tranceiver(NOP); _delay_us(10); PORTB |= _BV(CSN); //CSN high return reg; } void Write_byte(unsigned char reg, unsigned char data) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(W_REGISTER + reg); _delay_us(10); spi_tranceiver(data); _delay_us(10); PORTB |= _BV(CSN); //CSN high } void Init_nrf(void) { //Enable auto-acknowledgment for data pipe 0 Write_byte(EN_AA, 0x01); //Enable data pipe 0 Write_byte(EN_RXADDR, 0x01); //Set address width to 5 bytes Write_byte(SETUP_AW, 0x03); //Set channel frequency to 2.505GHz Write_byte(RF_CH, 0x69); //Set data rate to 2Mbps and 0dB gain Write_byte(RF_SETUP, 0x0E); //Enable W_TX_PAYLOAD_NOACK command // Write_byte(FEATURE, 0x01); //Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05 _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Setup p0 pipe address for receiving spi_tranceiver(W_REGISTER + RX_ADDR_P0); _delay_us(10); spi_tranceiver(0x11); _delay_us(10); spi_tranceiver(0x12); _delay_us(10); spi_tranceiver(0x13); _delay_us(10); spi_tranceiver(0x14); _delay_us(10); spi_tranceiver(0x15); _delay_us(10); PORTB |= _BV(CSN); //CSN high //Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05 _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Setup the transmitter address spi_tranceiver(W_REGISTER + TX_ADDR); _delay_us(10); spi_tranceiver(0xAA); _delay_us(10); spi_tranceiver(0xBB); _delay_us(10); spi_tranceiver(0xCC); _delay_us(10); spi_tranceiver(0xDD); _delay_us(10); spi_tranceiver(0xEE); _delay_us(10); PORTB |= _BV(CSN); //CSN high //Set the payload width as 8-bytes Write_byte(RX_PW_P0, 0x08); //Set the retransmission delay to 750us with 15 retries Write_byte(SETUP_RETR, 0x2F); //Boot the nrf as TX and mask the maximum retransmission interrupt(disable) //Enable CRC and set the length to 2-bytes nRF_TX_mode(); _delay_ms(10); //10ms delay after power-up } void nRF_TX_mode(void) { Flush_tx(); //Flush TX FIFO Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status PORTB &= ~_BV(CE); //CE low - Standby-I //Power-up and set as TX Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (0 << PRIM_RX)); //Mask TX_DR and MAX_RT interrupts Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)); _delay_us(150); } void nRF_RX_mode(void) { Flush_rx(); //Flush RX FIFO Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status PORTB &= ~_BV(CE); //CE low //Power-up as set as RX Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX)); //Mask TX_DR and MAX_RT interrupts Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)); PORTB |= _BV(CE); //CE high _delay_us(150); } void Flush_tx(void) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(FLUSH_TX); _delay_us(10); PORTB |= _BV(CSN); //CSN high _delay_us(10); } void Flush_rx(void) { _delay_us(10); PORTB &= ~_BV(CSN); _delay_us(10); spi_tranceiver(FLUSH_RX); _delay_us(10); PORTB |= _BV(CSN); _delay_us(10); } void Payload_TX(uint8_t* data, uint8_t len) { uint8_t i; for(i = 0; i < len; i++) { spi_tranceiver(BS_payload_TX[i]); } } void transmit_data(unsigned char *tdata) { Flush_tx(); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Transmit payload with ACK enabled spi_tranceiver(W_TX_PAYLOAD); _delay_us(10); Payload_TX(BS_payload_TX, PAYLOAD_LEN); _delay_us(10); PORTB |= _BV(CSN); //CSN high _delay_us(10); //Need at least 10us before sending PORTB |= _BV(CE); //CE high _delay_us(10); //Hold CE high for at least 10us and not longer than 4ms PORTB &= ~_BV(CE); //CE low } uint8_t nrf24_getStatus() { uint8_t rv; PORTB &= ~_BV(CSN); //CSN low rv = spi_tranceiver(NOP); PORTB |= _BV(CSN); //CSN high return rv; } uint8_t nrf24_isSending() { uint8_t status; /* read the current status */ status = nrf24_getStatus(); /* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */ if((status & ((1 << TX_DS) | (1 << MAX_RT)))) { return 0; /* false */ } return 1; /* true */ } void Init_INT6(void) { EICRB &= ~(1 << ISC60) | (1 << ISC61); //INT6 active when low EIMSK |= (1 << INT6); //Enable INT6 sei(); //Enable global interrupts } ISR(INT6_vect) { cli(); //Disable global interrupt PORTB &= ~_BV(CE); //Stop listening // Pull down chip select PORTB &= ~_BV(CSN); //CSN low _delay_us(10); // Send command to read RX payload spi_tranceiver(R_RX_PAYLOAD); _delay_us(10); // Read payload Payload_RX(BS_payload_RX, BS_payload_RX, PAYLOAD_LEN); _delay_us(10); // Pull up chip select PORTB |= _BV(CSN); //CSN high _delay_us(10); // Reset status register Write_byte(STATUS, (1 << RX_DR)); mode = 0; //Set as TX } /* send and receive multiple bytes over SPI */ void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len) { uint8_t i; for(i = 0; i < len; i++) { data_in[i] = spi_tranceiver(data_out[i]); UART_Tx(data_in[i]); //Send the received data to UART } } void reset(void) { _delay_us(10); //Reset IRQ-flags in status register Write_byte(STATUS, 0x70); _delay_us(10); } int main(void) { AVR_Init(); Init_SPI(); Init_nrf(); UART_Init(); Init_INT6(); //0 - TX; 1 - RX int8_t mode = 0; //Disable Interrupt initially cli(); //Endless Loop while(1) { if(mode == 0) //TX { //Configure as Transmitter nRF_TX_mode(); // UART_Tx(0x55); //Send BP1 to UART transmit_data(BS_payload_TX); while(nrf24_isSending()); reset(); // UART_Tx(0x66); //Send BP2 to UART //Configure as Receiver mode = 1; //Set as RX nRF_RX_mode(); PORTB |= _BV(CE); //Start listening again sei(); // UART_Tx(0x77); //Send BP3 to UART } // UART_Tx(0x88); //Send BP4 to UART } }
Node code:
/* * Node_1.c * * Created: 21-Nov-18 6:21:39 PM * Author : Frederic Philips */ #include <avr/io.h> #include <avr/sfr_defs.h> #include <stdint.h> #include <stdlib.h> #define F_CPU 16000000UL //16 MHz frequency #define BAUD 57600 #include <util/setbaud.h> #include <util/delay.h> #include <avr/interrupt.h> #include "Test_BNO055.h" #include "i2cmaster.h" #include "nrf.h" #define MOSI 2 #define MISO 3 #define SCLK 1 #define CSN 0 #define CE 4 #define PAYLOAD_LEN 8 uint8_t N1_payload_TX[PAYLOAD_LEN]; uint8_t N1_payload_RX[PAYLOAD_LEN]; volatile uint8_t RX_Payload_cnt; void nRF_TX_mode(void); void nRF_RX_mode(void); void Flush_tx(void); void Flush_rx(void); void reset(void); void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len); uint8_t nrf24_getStatus(void); uint8_t nrf24_isSending(void); /************************************************************************************ ** AVR_Init function: ** - Start-up delay ** - Initializes the I/O peripherals *************************************************************************************/ void AVR_Init(void) { _delay_ms(750); //Short pause after BNO055 Power-On Reset(Mandatory) DDRD |= _BV(1); //Set TX as output DDRD &= ~(_BV(0)); //Set RX as input //Initialize TWI data TWI_data = 0; } /************************************************************************************ ** USART Reference: ** - ATmega32U4 Datasheet - Rev. CORP072610(Pg.186) ** - AVR Microcontroller and Embedded Systems - Mazidi(Pg.395) ** - Embedded C Programming and the Atmel AVR - Barnett(Pg.132) ************************************************************************************* ** To initialize the UART, the following steps are to be followed: ** - Set the Baud rate(use <util/setbaud.h>, which depends on the macros F_CPU & BAUD) ** - Disable double speed(2x) mode ** - Set the no. of data bits(8/9 bits), stop bit(1/2) and parity bit(None/Odd/Even) ** - Set the USART mode(Synchronous/Asynchronous/Asynchronous 2x) ** - Enable Receiver & Transmitter(Set RXEN & TXEN bits in UCSRB register) *************************************************************************************/ void UART_Init(void) { DDRD |= _BV(1); //Set TX as output DDRD &= ~(_BV(0)); //Set RX as input //Set the BAUD rate(Ref. ATmega32U4 Datasheet Pg.189, Table 18-1) //To hard-code the Baud rate, Ref. Tables 18-9 to 18-12 in Pgs. 210 - 213 UBRR1 = ((F_CPU / (16UL * BAUD)) - 1); //Disables 2x speed UCSR1A &= ~(_BV(U2X1)); //Enable 8-bit character size, one stop-bit, no parity & asynchronous mode UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10); //Enable Transmitter & Receiver UCSR1B |= _BV(TXEN1) | _BV(RXEN1); } /************************************************************************************ ** UART_Tx function: ** - Transmits the ADC data via the USB Serial ** - The data is received & displayed in a Hyperterminal *************************************************************************************/ void UART_Tx(unsigned char data) { loop_until_bit_is_set(UCSR1A, UDRE1); //Wait until buffer is empty UDR1 = data; //Send data } void BNO_Read_Quaternions(void) { i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_W_LSB_ADDR); //Access LSB of Quaternion_W value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[0] = i2c_readNak(); UART_Tx(N1_payload_TX[0]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_W_MSB_ADDR); //Access MSB of Quaternion_W value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[1] = i2c_readNak(); UART_Tx(N1_payload_TX[1]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_X_LSB_ADDR); //Access LSB of Quaternion_X value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[2] = i2c_readNak(); UART_Tx(N1_payload_TX[2]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_X_MSB_ADDR); //Access MSB of Quaternion_X value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[3] = i2c_readNak(); UART_Tx(N1_payload_TX[3]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_Y_LSB_ADDR); //Access LSB of Quaternion_Y value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[4] = i2c_readNak(); UART_Tx(N1_payload_TX[4]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_Y_MSB_ADDR); //Access MSB of Quaternion_Y value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[5] = i2c_readNak(); UART_Tx(N1_payload_TX[5]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_Z_LSB_ADDR); //Access LSB of Quaternion_Z value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[6] = i2c_readNak(); UART_Tx(N1_payload_TX[6]); i2c_stop(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_QUATERNION_DATA_Z_MSB_ADDR); //Access MSB of Quaternion_Z value i2c_rep_start(BNO055_ADDRESS+I2C_READ); //Set device address and read mode N1_payload_TX[7] = i2c_readNak(); UART_Tx(N1_payload_TX[7]); i2c_stop(); } void Init_SPI() { //Set the output pin(s) for SPI DDRB |= _BV(CE); //CE DDRB |= _BV(CSN); //CSN DDRB |= _BV(MOSI); //MOSI DDRB |= _BV(SCLK); //SCLK //Set the input pin(s) for SPI DDRB &= ~_BV(MISO); //MISO SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0)); //Enable SPI as master SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); //Set clock rate but not too important PORTB |= _BV(CSN); //CSN high PORTB &= ~_BV(CE); //CE low _delay_ms(10); //10ms delay } unsigned char spi_tranceiver(unsigned char data) { //Load data into the buffer SPDR = data; //Wait until transmission complete while(!(SPSR & (1 << SPIF))); //Return received data return(SPDR); } unsigned char Read_Byte(unsigned char reg) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(R_REGISTER + reg); _delay_us(10); reg = spi_tranceiver(NOP); _delay_us(10); PORTB |= _BV(CSN); //CSN high return reg; } void Write_byte(unsigned char reg, unsigned char data) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(W_REGISTER + reg); _delay_us(10); spi_tranceiver(data); _delay_us(10); PORTB |= _BV(CSN); //CSN high } void Init_nrf(void) { //Enable auto-acknowledgment for data pipe 0 Write_byte(EN_AA, 0x01); //Enable data pipe 0 Write_byte(EN_RXADDR, 0x01); //Set address width to 5 bytes Write_byte(SETUP_AW, 0x03); //Set channel frequency to 2.505GHz Write_byte(RF_CH, 0x69); //Set data rate to 2Mbps and 0dB gain Write_byte(RF_SETUP, 0x0E); //Enable W_TX_PAYLOAD_NOACK command // Write_byte(FEATURE, 0x01); //Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05 _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Setup p0 pipe address for receiving spi_tranceiver(W_REGISTER + RX_ADDR_P0); _delay_us(10); spi_tranceiver(0xAA); _delay_us(10); spi_tranceiver(0xBB); _delay_us(10); spi_tranceiver(0xCC); _delay_us(10); spi_tranceiver(0xDD); _delay_us(10); spi_tranceiver(0xEE); _delay_us(10); PORTB |= _BV(CSN); //CSN high //Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05 _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Setup the transmitter address spi_tranceiver(W_REGISTER + TX_ADDR); _delay_us(10); spi_tranceiver(0x11); _delay_us(10); spi_tranceiver(0x12); _delay_us(10); spi_tranceiver(0x13); _delay_us(10); spi_tranceiver(0x14); _delay_us(10); spi_tranceiver(0x15); _delay_us(10); PORTB |= _BV(CSN); //CSN high //Set the payload width as 8-bytes Write_byte(RX_PW_P0, 0x08); //Set the retransmission delay to 750us with 15 retries Write_byte(SETUP_RETR, 0x2F); //Boot the nrf as RX and mask the maximum retransmission interrupt(disable) //Enable CRC and set the length to 2-bytes nRF_RX_mode(); _delay_ms(10); //10ms delay after power-up } void nRF_TX_mode(void) { Flush_tx(); //Flush TX FIFO Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status PORTB &= ~_BV(CE); //CE low - Standby-I //Power-up and set as TX Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (0 << PRIM_RX)); //Mask TX_DR and MAX_RT interrupts Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)); _delay_us(150); } void nRF_RX_mode(void) { Flush_rx(); //Flush RX FIFO Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status PORTB &= ~_BV(CE); //CE low //Power-up as set as RX Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX)); //Mask TX_DR and MAX_RT interrupts Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)); PORTB |= _BV(CE); //CE high _delay_us(150); } void Flush_tx(void) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(FLUSH_TX); _delay_us(10); PORTB |= _BV(CSN); //CSN high _delay_us(10); } void Flush_rx(void) { _delay_us(10); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); spi_tranceiver(FLUSH_RX); _delay_us(10); PORTB |= _BV(CSN); //CSN high _delay_us(10); } void Payload_TX(uint8_t* data, uint8_t len) { uint8_t i; for(i = 0; i < len; i++) { spi_tranceiver(N1_payload_TX[i]); } } void transmit_data(unsigned char *tdata) { Flush_tx(); PORTB &= ~_BV(CSN); //CSN low _delay_us(10); //Transmit payload with ACK enabled spi_tranceiver(W_TX_PAYLOAD); _delay_us(10); Payload_TX(N1_payload_TX, PAYLOAD_LEN); _delay_us(10); PORTB |= _BV(CSN); //CSN high _delay_us(10); //Need at least 10us before sending PORTB |= _BV(CE); //CE high _delay_us(10); //Hold CE high for at least 10us and not longer than 4ms PORTB &= ~_BV(CE); //CE low } uint8_t nrf24_getStatus() { uint8_t rv; PORTB &= ~_BV(CSN); //CSN low rv = spi_tranceiver(NOP); PORTB |= _BV(CSN); //CSN high return rv; } uint8_t nrf24_isSending() { uint8_t status; /* read the current status */ status = nrf24_getStatus(); /* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */ if((status & ((1 << TX_DS) | (1 << MAX_RT)))) { return 0; /* false */ } return 1; /* true */ } void Init_INT6(void) { EICRB &= ~(1 << ISC60) | (1 << ISC61); //INT6 active when low EIMSK |= (1 << INT6); //Enable INT6 sei(); //Enable global interrupts } ISR(INT6_vect) { cli(); //Disable global interrupt PORTB &= ~_BV(CE); //Stop listening // Pull down chip select PORTB &= ~_BV(CSN); //CSN low _delay_us(10); // Send command to read RX payload spi_tranceiver(R_RX_PAYLOAD); _delay_us(10); // Read payload Payload_RX(N1_payload_RX, N1_payload_RX, PAYLOAD_LEN); _delay_us(10); // Pull up chip select PORTB |= _BV(CSN); //CSN high _delay_us(10); // Reset status register Write_byte(STATUS, (1 << RX_DR)); } /* send and receive multiple bytes over SPI */ void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len) { uint8_t i; for(i=0; i<len; i++) { data_in[i] = spi_tranceiver(data_out[i]); UART_Tx(data_in[i]); //Send the received data to UART if (data_in[i] == 0xAA) { RX_Payload_cnt++; UART_Tx(RX_Payload_cnt); //Send RX_Payload count to UART } } } void reset(void) { _delay_us(10); //Reset IRQ-flags in status register Write_byte(STATUS, 0x70); _delay_us(10); } /************************************************************************************ ** Main function: ** - Contains an endless loop ** - Sets the BNO055 in NDOF mode and fetches the quaternion data *************************************************************************************/ int main(void) { AVR_Init(); i2c_init(); Init_SPI(); Init_nrf(); UART_Init(); Init_INT6(); i2c_start_wait(BNO055_ADDRESS+I2C_WRITE); //Set device address and read mode i2c_write(BNO055_OPR_MODE_ADDR); i2c_write(OPERATION_MODE_NDOF); //Set operation mode to NDOF i2c_stop(); _delay_ms(10); //Initialize the received payload count RX_Payload_cnt = 0; Flush_rx(); reset(); PORTB |= _BV(CE); //Start listening //Endless Loop while(1) { if (RX_Payload_cnt == PAYLOAD_LEN) { UART_Tx(0x55); //Send BP1 to UART RX_Payload_cnt = 0; //Configure as Transmitter nRF_TX_mode(); UART_Tx(0x66); //Send BP2 to UART //Read the Quaternions data from the BNO055 BNO_Read_Quaternions(); UART_Tx(0x77); //Send BP3 to UART //Transmit Quaternion payload transmit_data(N1_payload_TX); while(nrf24_isSending()); reset(); UART_Tx(0x88); //Send BP4 to UART //Configure as Receiver nRF_RX_mode(); Flush_rx(); reset(); PORTB |= _BV(CE); //Start listening again sei(); UART_Tx(0x99); //Send BP5 to UART } // UART_Tx(0x00); //Send BP5 to UART } }