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
}
}