Hi I am working on a project where I am trying to implement Bi-directional communication between 2 nrf modules connected to stm32f411ve dev boards.
I am facing issue with adding a dynamic payload along with my ack message
below is nrf driver code for the receiver side and also the spi code.
I am unable to understand how and where should I call the W_TX_PAYLOAD command
/*
* SPI.c
*
* Created on: Nov 10, 2024
* Author: Asus
*/
#include"SPI.h"
#include"stdio.h"
#define AF05 (0x05)
void SPI_INIT(){
//enable clock for GPIOA
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
//set PA5, PA6 and PA7 to alternate function mode
GPIOA->MODER|=GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1;
//set which type of alternate function is
GPIOA->AFR[0]|=(AF05<<20)|(AF05<<24)|(AF05<<28);
//enable clock access to SPI1
RCC->APB2ENR|=RCC_APB2ENR_SPI1EN;
//set software slave managment
SPI1->CR1|=SPI_CR1_SSM|SPI_CR1_SSI;
//set SPI in master mode
MODIFY_FIELD(SPI1->CR1, SPI_CR1_MSTR, 1);
MODIFY_FIELD(SPI1->CR1, SPI_CR1_BR, 3);
MODIFY_FIELD(SPI1->CR1, SPI_CR1_CPHA, 0);
MODIFY_FIELD(SPI1->CR1, SPI_CR1_CPOL, 0);
//MODIFY_FIELD(SPI1->CR1, SPI_CR1_LSBFIRST, 1);
SPI1->CR2 |= 0x4;
SPI1->CR1 |= 0x40; // Enabling SPI SPI periph
MODIFY_FIELD(SPI1->CR1, SPI_CR1_SPE, 1);
}
//send multiple bytes in case size>1
void SPI_TX_MULTI(uint8_t *data_ptr,int size){
int i=0;
uint8_t temp;
while(i<size){
while(!(SPI1->SR & (SPI_SR_TXE))){}
SPI1->DR = data_ptr[i];
i++;
}
/*Wait until TXE is set*/
while(!(SPI1->SR & (SPI_SR_TXE))){}
/*Wait for BUSY flag to reset*/
while((SPI1->SR & (SPI_SR_BSY))){}
/*Clear OVR flag*/
temp = SPI1->DR;
temp = SPI1->SR;
}
void SPI_READ_MULTI(uint8_t *data_ptr,int size){
while(size)
{
/*Send dummy data*/
SPI1->DR =0;
/*Wait for RXNE flag to be set*/
while(!(SPI1->SR & (SPI_SR_RXNE))){}
/*Read data from data register*/
*data_ptr++ = (SPI1->DR);
size--;
}
}
/*
* NRF_DRIVER.c
*
* Created on: Nov 10, 2024
* Author: Asus
*/
#include"NRF_DRIVER.h"
#include"delay.h"
#include"SPI.h"
#include"utilities.h"
#include<stdio.h>
void init_CSN_CE_PINS(){
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
MODIFY_FIELD(GPIOA->MODER, GPIO_MODER_MODER4, ESF_GPIO_MODER_OUTPUT); // NSS pin for now4 as outpu
MODIFY_FIELD(GPIOA->MODER, GPIO_MODER_MODER0, ESF_GPIO_MODER_OUTPUT); // NSS pin for now4 as outpu
}
void CSN_SELECT_NRF(){
GPIOA->BSRR |= GPIO_BSRR_BR_4; //pull low to enable nrf
}
void CSN_UNSELECT_NRF(){
GPIOA->BSRR |= GPIO_BSRR_BS_4; //make high to disable
}
void NRF_ENABLE(){
GPIOA->BSRR |= GPIO_BSRR_BS_0;
}
void NRF_DISABLE(){
GPIOA->BSRR |= GPIO_BSRR_BR_0;
}
void NRF_WRITE_REGISTER(uint8_t REG_ADDRESS,uint8_t data){
uint8_t trans_buff[2];
trans_buff[0]=REG_ADDRESS|W_REGISTER;
trans_buff[1]=data;
CSN_SELECT_NRF();
SPI_TX_MULTI(trans_buff,2);
CSN_UNSELECT_NRF();
}
void NRF_WRITE_REG_MULTI_BYTES(uint8_t REG_ADDRESS,uint8_t* data_trans,int size_trans){
uint8_t trans_buff[2];
trans_buff[0]=REG_ADDRESS|W_REGISTER;
CSN_SELECT_NRF();
SPI_TX_MULTI(trans_buff,1);
SPI_TX_MULTI(data_trans,size_trans);
CSN_UNSELECT_NRF();
}
uint8_t NRF_READ_REGISTER(uint8_t REG_ADDRESS){
uint8_t data_returned=0;
CSN_SELECT_NRF();
SPI_TX_MULTI(®_ADDRESS,1);
SPI_READ_MULTI(&data_returned,1);
CSN_UNSELECT_NRF();
return data_returned;
}
void NRF_READ_REGISTER_MULTI(uint8_t REG_ADDRESS,uint8_t *RECV_BUFFER,int RECV_BUFFER_SIZE){
CSN_SELECT_NRF();
SPI_TX_MULTI(®_ADDRESS,1);
SPI_READ_MULTI(RECV_BUFFER,RECV_BUFFER_SIZE);
CSN_UNSELECT_NRF();
}
void NRF_PTX_CONFIG(uint8_t *Address, uint8_t channel){
NRF_DISABLE();
NRF_WRITE_REGISTER(RF_CH,channel); //select channel
NRF_WRITE_REG_MULTI_BYTES(TX_ADDR,Address,5); //set address
// un comment belowo code to setup for auto ack
uint8_t current_pipe_status=NRF_READ_REGISTER(EN_RXADDR);
current_pipe_status=current_pipe_status|(1<<0);//enable pipe 1
NRF_WRITE_REGISTER(EN_RXADDR,current_pipe_status);
NRF_WRITE_REG_MULTI_BYTES(RX_ADDR_P0,Address,5); //pipe address
NRF_WRITE_REGISTER(CONFIG,0x0a); //powwr on device and keep in tx mode
delay(5);
//NRF_ENABLE();
}
void NRF_PRX_CONFIG(uint8_t *Address, uint8_t channel){
NRF_DISABLE();
NRF_WRITE_REGISTER(RF_CH,channel); //select channel
uint8_t current_pipe_status=NRF_READ_REGISTER(EN_RXADDR);
current_pipe_status=current_pipe_status|(1<<1);//enable pipe 1
NRF_WRITE_REGISTER(EN_RXADDR,current_pipe_status);
NRF_WRITE_REG_MULTI_BYTES(RX_ADDR_P1,Address,5); //pipe address
//since we have dynamic payload we dont need thus below
//NRF_WRITE_REGISTER(RX_PW_P1,32); //data 32 bytes width
NRF_WRITE_REGISTER(CONFIG,0x0b); //powwr on device and keep in tx mode
NRF_ENABLE();
}
void nrf24_reset(uint8_t REG)
{
if (REG == STATUS)
{
NRF_WRITE_REGISTER(STATUS, 0x00);
}
else if (REG == FIFO_STATUS)
{
NRF_WRITE_REGISTER(FIFO_STATUS, 0x11);
}
else {
NRF_WRITE_REGISTER(CONFIG, 0x08);
NRF_WRITE_REGISTER(EN_AA, 0x3F);
NRF_WRITE_REGISTER(EN_RXADDR, 0x03);
NRF_WRITE_REGISTER(SETUP_AW, 0x03);
NRF_WRITE_REGISTER(SETUP_RETR, 0x03);
NRF_WRITE_REGISTER(RF_CH, 0x02);
NRF_WRITE_REGISTER(RF_SETUP, 0x0E);
NRF_WRITE_REGISTER(STATUS, 0x00);
NRF_WRITE_REGISTER(OBSERVE_TX, 0x00);
NRF_WRITE_REGISTER(CD, 0x00);
uint8_t rx_addr_p0_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
NRF_WRITE_REG_MULTI_BYTES(RX_ADDR_P0, rx_addr_p0_def, 5);
uint8_t rx_addr_p1_def[5] = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2};
NRF_WRITE_REG_MULTI_BYTES(RX_ADDR_P1, rx_addr_p1_def, 5);
NRF_WRITE_REGISTER(RX_ADDR_P2, 0xC3);
NRF_WRITE_REGISTER(RX_ADDR_P3, 0xC4);
NRF_WRITE_REGISTER(RX_ADDR_P4, 0xC5);
NRF_WRITE_REGISTER(RX_ADDR_P5, 0xC6);
uint8_t tx_addr_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
NRF_WRITE_REG_MULTI_BYTES(TX_ADDR, tx_addr_def, 5);
NRF_WRITE_REGISTER(RX_PW_P0, 0);
NRF_WRITE_REGISTER(RX_PW_P1, 0);
NRF_WRITE_REGISTER(RX_PW_P2, 0);
NRF_WRITE_REGISTER(RX_PW_P3, 0);
NRF_WRITE_REGISTER(RX_PW_P4, 0);
NRF_WRITE_REGISTER(RX_PW_P5, 0);
NRF_WRITE_REGISTER(FIFO_STATUS, 0x11);
NRF_WRITE_REGISTER(DYNPD, 0);
NRF_WRITE_REGISTER(FEATURE, 0);
}
}
void NRF_INIT(){
SPI_INIT(); //initalize spi comms
init_CSN_CE_PINS();
NRF_DISABLE();
nrf24_reset(0);
NRF_WRITE_REGISTER(CONFIG, 0); // will be configured later
//NRF_WRITE_REGISTER(EN_AA, 0x00); // No Auto ACK
/*uncomment below code to enable auto ack stuff*/
//NRF_WRITE_REGISTER(EN_AA, 0x3f); // No Auto ACK
//NRF_WRITE_REGISTER(SETUP_RETR, 0x03); // 15 retries, 500µs delay
NRF_WRITE_REGISTER (EN_RXADDR, 0); // Not Enabling any data pipe right now
NRF_WRITE_REGISTER (SETUP_AW, 0x03); // 5 Bytes for the TX/RX address
//NRF_WRITE_REGISTER (SETUP_RETR, 0x00); // No retransmission
NRF_WRITE_REGISTER (RF_CH, 0); // will be setup during Tx or RX
//enable dynamic payloads on all pipes
//for DYNP I require EN_AA and Requires EN_DPL and ENAA_P0
NRF_WRITE_REGISTER (DYNPD, 0x3f); // will be setup during Tx or RX
NRF_WRITE_REGISTER (FEATURE, 0x6); // enable dynamic payload length
NRF_WRITE_REGISTER(EN_AA, 0x3f); // No Auto ACK
NRF_WRITE_REGISTER(SETUP_RETR, 0xff); // 15 retries, 500µs delay
NRF_WRITE_REGISTER (RF_SETUP, 0x0e); // Power= 0db, data rate = 2Mbps
//NRF_ENABLE();
}
void NRD_SEND_CMD (uint8_t cmd)
{
// Pull the CS Pin LOW to select the device
CSN_SELECT_NRF();
SPI_TX_MULTI(&cmd, 1);
// Pull the CS HIGH to release the device
CSN_UNSELECT_NRF();
}
uint8_t NRF_TX_DATA(uint8_t *data_ptr){
uint8_t tx_fifo_stat;
uint8_t status_reg;
CSN_SELECT_NRF();
uint8_t cmd = W_TX_PAYLOAD;
SPI_TX_MULTI( &cmd, 1);
SPI_TX_MULTI(data_ptr,32);//send payload
CSN_UNSELECT_NRF();
NRF_ENABLE();
delay(10);
NRF_DISABLE();
tx_fifo_stat=NRF_READ_REGISTER(FIFO_STATUS);
status_reg=NRF_READ_REGISTER(STATUS);
printf("tx_fifo_stat is - %d",tx_fifo_stat);
printf("status register- %d",status_reg);
if ((tx_fifo_stat&(1<<4)) && (!(tx_fifo_stat&(1<<3)))){
cmd=FLUSH_TX;
NRD_SEND_CMD(cmd);
NRF_WRITE_REGISTER(FIFO_STATUS, 0x11); //reset fifo
return 1;
}
if(status_reg &(1<<4)){
printf("max number of retransmission \n \r %d \n \r",status_reg);
status_reg=status_reg|(1<<4);
NRF_WRITE_REGISTER(STATUS,status_reg);
status_reg=NRF_READ_REGISTER(STATUS);
printf("after clearing flag? %d \n \r",status_reg);
cmd=FLUSH_TX;
NRD_SEND_CMD(cmd);
NRF_WRITE_REGISTER(FIFO_STATUS, 0x11); //reset fifo
}
return 0;
}
uint8_t is_data_on_pipe(uint8_t pipenum){
uint8_t status_reg=NRF_READ_REGISTER(STATUS);
//if 6 th bit is set and respective data pipe is set
//printf("reciever status %d \n \r",status_reg);
if((status_reg & (1<<6))&& status_reg &(1<<pipenum)){
//clear rx_dr
NRF_WRITE_REGISTER(STATUS,(1<<6));
return 1; //data recieved
}
return 0;
}
//uint8_t NRF_SEND_PAYLOAD_WIDTH_READ(uint8_t cmd){
// uint8_t temp;
// while(!(SPI1->SR & (SPI_SR_TXE))){}
// SPI1->DR = cmd;
// temp = SPI1->DR;
// temp = SPI1->SR;
// while (!(SPI1->SR & SPI_SR_RXNE)) {}
// return (uint8_t)(SPI1->DR);
//}
//this code needs to be modefied for dyanmic first we will send
//R_RX_PL_WID first and then R_RX_PAYLOAD
void NRF_RECV_DATA(uint8_t *data_ptr_RECV){
CSN_SELECT_NRF();
uint8_t cmd=W_ACK_PAYLOAD|0;
SPI_TX_MULTI( &cmd, 1);
uint8_t ack_payLoad[]={0x56};
SPI_TX_MULTI(ack_payLoad, sizeof(ack_payLoad));
CSN_UNSELECT_NRF();
delay(10);
uint8_t status_reg=NRF_READ_REGISTER(STATUS);
uint8_t tx_fifo_stat=NRF_READ_REGISTER(FIFO_STATUS);
delay(10);
cmd = R_RX_PL_WID;
uint8_t payLoad_width=0;
CSN_SELECT_NRF();
//payLoad_width=NRF_SEND_PAYLOAD_WIDTH_READ(cmd);
//next comand to read payload
SPI_TX_MULTI( &cmd, 1);
SPI_READ_MULTI(&payLoad_width,1);//recieve width
printf("\n \r payloadWidth %d \n \r",payLoad_width);
CSN_UNSELECT_NRF();
delay(10);
printf("status_reg %d \n \r",status_reg);
printf("tx_fifo_stat %d \n \r",tx_fifo_stat);
CSN_SELECT_NRF();
cmd=R_RX_PAYLOAD;
SPI_TX_MULTI( &cmd, 1);
SPI_READ_MULTI(data_ptr_RECV,payLoad_width);//recieve data
CSN_UNSELECT_NRF();
cmd=FLUSH_RX;
delay(20);
NRD_SEND_CMD(cmd); //flush rx fifo
delay(10);
if(tx_fifo_stat&(1<<5)){
cmd=FLUSH_TX;
NRD_SEND_CMD(cmd);
}
}
Thanks