nrf control, stub of sending data

retry
Ondřej Hruška 7 years ago
parent e738c1e3a8
commit 6c4c5fb1fd
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 15
      Inc/crc32.h
  2. 3
      Inc/gex_gateway.h
  3. 3
      Inc/msg_queue.h
  4. 157
      Inc/nrf.h
  5. 2
      Makefile
  6. 67
      Src/crc32.c
  7. 150
      Src/gex_gateway.c
  8. 4
      Src/gpio.c
  9. 24
      Src/main.c
  10. 3
      Src/msg_queue.c
  11. 470
      Src/nrf.c
  12. 5
      Src/spi.c

@ -0,0 +1,15 @@
//
// Created by MightyPork on 2018/04/03.
//
#ifndef GEX_NRF_CRC32_H
#define GEX_NRF_CRC32_H
uint32_t CRC32_Start(void);
uint32_t CRC32_Add(uint32_t cksum, uint8_t byte);
uint32_t CRC32_End(uint32_t cksum);
#endif //GEX_NRF_CRC32_H

@ -6,7 +6,8 @@
#define GEX_NRF_GEX_GATEWAY_H
#include "main.h"
void gw_process(void);
void gw_handle_usb_out(uint8_t *buffer);
void gw_setup_radio(void);
#endif //GEX_NRF_GEX_GATEWAY_H

@ -21,8 +21,7 @@ typedef struct {
volatile uint32_t nw;
} MQueue;
extern MQueue usb_rxq;
extern MQueue usb_txq;
extern MQueue usb_inq;
void mq_init(MQueue *mq);

@ -0,0 +1,157 @@
//
// Created by MightyPork on 2018/04/02.
//
#ifndef GEX_NRF_NRF_H
#define GEX_NRF_NRF_H
/*
* nordic.h
*
* Created:12/16/2013 3:36:04 PM
* Author: Tom
*
* NRF24L01+ Library II
*
*/
#ifndef NORDIC_H_
#define NORDIC_H_
#include "main.h"
// Initialize SPI and the Nordic
/**
* Initialize the NRF module
*
* @param pSpeed
*/
void NRF_Init(uint8_t pSpeed);
#define NRF_SPEED_500k 0b00100110
#define NRF_SPEED_2M 0b00001110
#define NRF_SPEED_1M 0b00000110
/**
* Set reception address
* @param pipenum - pipe to set
* @param AddrByte - byte 0
*/
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte);
/**
* Set communication channel
*/
void NRF_SetChannel(uint8_t Ch) ; // 0 through 83 only!
/**
* Power down the transceiver
*/
void NRF_PowerDown(void);
/**
* Selecr RX mode
*/
void NRF_ModeRX(void);
/**
* Select TX mode
*/
void NRF_ModeTX(void);
/**
* @return NRF is power down
*/
uint8_t NRF_IsModePowerDown(void);
/**
* @return NRF in TX mode
*/
uint8_t NRF_IsModeTX(void);
/**
* @return NRF in RX mode
*/
uint8_t NRF_IsModeRx(void);
/**
* Add a pipe to the next free slot
*
* @param AddrByte - address byte of the peer
* @param[out] PipeNum - pipe number is written here
* @return success
*/
bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum);
/**
* Convert pipe number to address byte
*
* @param pipe_num - pipe number
* @return address byte
*/
uint8_t NRF_PipeNum2Addr(uint8_t pipe_num);
/**
* Convert address to a pipe number
*
* @param addr
* @return
*/
uint8_t NRF_Addr2PipeNum(uint8_t addr);
/**
* Reset as much as possible (incl. removing pipes)
*/
void NRF_Reset(void);
/**
* Send a packet (takes care of mode switching etc)
*
* @param PipeNum - pipe number
* @param Packet - packet bytes
* @param Length - packet length
* @return success (ACK'd)
*/
bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length);
/**
* Receive a packet
*
* @param[out] Packet - the receiuved packet - buffer that is written
* @param[out] PipeNum - pipe number that was received from
* @return packet size, 0 on failure
*/
uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum);
/**
* Set base address
* @param Bytes4
*/
void NRF_SetBaseAddress(const uint8_t *Bytes4);
/**
* Check if there's a packet to be read
*
* @return 1 if any to read
*/
bool NRF_IsRxPacket(void);
/**
* Enable a pipe
*
* @param pipenum - pipe number 0-5
*/
void NRF_EnablePipe(uint8_t pipenum);
/**
* Disable a pipe
*
* @param pipenum - pipe number 0-5
*/
void NRF_DisablePipe(uint8_t pipenum);
#endif /* NORDIC_H_ */
#endif //GEX_NRF_NRF_H

@ -67,6 +67,8 @@ Src/msg_queue.c \
Src/gex_gateway.c \
Src/payload_builder.c \
Src/payload_parser.c \
Src/nrf.c \
Src/crc32.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \

@ -0,0 +1,67 @@
//
// Created by MightyPork on 2018/04/03.
//
#include "main.h"
#include "crc32.h"
static const uint32_t crc32_table[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t CRC32_Start(void)
{
return (uint32_t) 0xFFFFFFFF;
}
uint32_t CRC32_Add(uint32_t cksum, uint8_t byte)
{
return crc32_table[((cksum) ^ ((uint8_t) byte)) & 0xff] ^ ((cksum) >> 8);
}
uint32_t CRC32_End(uint32_t cksum)
{
return (uint32_t) ~cksum;
}

@ -9,49 +9,61 @@
#include "main.h"
#include "minmax.h"
#include "payload_parser.h"
#include "nrf.h"
#include "crc32.h"
#include "payload_builder.h"
static uint8_t gex_network[4];
// USB RX
enum URX_STATE {
URXS_IDLE = 0,
URXS_MSG4SLAVE = 1,
enum USB_RX_STATE {
CMD_STATE_IDLE = 0,
CMD_STATE_TXMSG = 1,
};
#define MAX_FRAME_LEN 512
static enum URX_STATE urx_state = URXS_IDLE;
static uint32_t msg4slave_len = 0; // total len to be collected
static uint32_t msg4slave_already = 0; // already collected len
static uint8_t msg4slave[MAX_FRAME_LEN]; // equal buffer size in GEX
static uint8_t msg4slave_addr = 0;
static uint8_t msg4slave_cksum = 0;
static enum USB_RX_STATE cmd_state = CMD_STATE_IDLE;
static uint32_t txmsg_len = 0; // total len to be collected
static uint32_t txmsg_collected = 0; // already collected len
static uint8_t txmsg_payload[MAX_FRAME_LEN]; // equal buffer size in GEX
static uint8_t txmsg_addr = 0;
static uint8_t txmsg_cksum = 0;
#define MAGIC_GW_COMMAND 0x47U // 'G'
enum GW_CMD {
CMD_GET_ID = 'i', // 105
CMD_MSG4SLAVE = 'm', // 109
CMD_GET_ID = 'i', // 105 - get network ID
CMD_RESET = 'r', // reset the radio and network
CMD_ADD_NODE = 'n', // add a node by address byte
CMD_TXMSG = 'm', // 109 - send a message
};
void respond_gw_id() {} // TODO impl
void respond_gw_id(void);
void handle_cmd_addnode(PayloadParser *pp);
void handle_cmd_reset(void);
void start_slave_cmd(uint8_t slave_addr, uint16_t frame_len, uint8_t cksum)
{
msg4slave_len = frame_len;
msg4slave_already = 0;
msg4slave_addr = slave_addr;
msg4slave_cksum = cksum;
txmsg_len = frame_len;
txmsg_collected = 0;
txmsg_addr = slave_addr;
txmsg_cksum = cksum;
}
void gw_handle_usb_out(uint8_t *buffer)
{
if (urx_state == URXS_IDLE) {
if (cmd_state == CMD_STATE_IDLE) {
PayloadParser pp = pp_start(buffer, MQ_SLOT_LEN, NULL);
// handle binary commands for the gateway
// magic twice, one inverted - denotes a gateway command
uint16_t magic1 = pp_u8(&pp);
uint16_t magic2 = pp_u8(&pp);
const uint16_t magic1 = pp_u8(&pp);
const uint16_t magic2 = pp_u8(&pp);
if (magic1 == MAGIC_GW_COMMAND && magic2 == (0xFFU & (~MAGIC_GW_COMMAND))) {
// third byte is the command code
switch (pp_u8(&pp)) {
@ -59,7 +71,15 @@ void gw_handle_usb_out(uint8_t *buffer)
respond_gw_id();
break;
case CMD_MSG4SLAVE:;
case CMD_RESET:
handle_cmd_reset();
break;
case CMD_ADD_NODE:
handle_cmd_addnode(&pp);
break;
case CMD_TXMSG:;
uint8_t slave_addr = pp_u8(&pp);
uint16_t frame_len = pp_u16(&pp);
uint8_t cksum = pp_u8(&pp);
@ -71,7 +91,7 @@ void gw_handle_usb_out(uint8_t *buffer)
start_slave_cmd(slave_addr, frame_len, cksum);
dbg("Collecting frame for slave %02x: %d bytes", (int)slave_addr, (int)frame_len);
urx_state = URXS_MSG4SLAVE;
cmd_state = CMD_STATE_TXMSG;
break;
default:
@ -82,38 +102,96 @@ void gw_handle_usb_out(uint8_t *buffer)
dbg("Bad USB frame, starts %x,%x", buffer[0],buffer[1]);
}
}
else if (urx_state == URXS_MSG4SLAVE) {
uint32_t wanted = MIN(msg4slave_len-msg4slave_already, MQ_SLOT_LEN);
memcpy(&msg4slave[msg4slave_already], buffer, wanted);
msg4slave_already += wanted;
else if (cmd_state == CMD_STATE_TXMSG) {
uint32_t wanted = MIN(txmsg_len - txmsg_collected, MQ_SLOT_LEN);
memcpy(&txmsg_payload[txmsg_collected], buffer, wanted);
txmsg_collected += wanted;
if (wanted < MQ_SLOT_LEN) {
// this was the end
uint8_t ck = 0;
for (int i = 0; i < msg4slave_len; i++) {
ck ^= msg4slave[i];
for (int i = 0; i < txmsg_len; i++) {
ck ^= txmsg_payload[i];
}
ck = ~ck;
if (ck != msg4slave_cksum) {
if (ck != txmsg_cksum) {
dbg("Checksum mismatch!");
}
else {
dbg("Verified, sending a %d B frame to slave.", (int) msg4slave_len);
dbg("Verified, sending a %d B frame to slave.", (int) txmsg_len);
// TODO send to slave
}
urx_state = URXS_IDLE;
cmd_state = CMD_STATE_IDLE;
}
}
}
/** called from the main loop, periodically */
void gw_process(void)
void handle_cmd_reset(void)
{
NRF_Reset();
// TODO also clear queues?
}
void handle_cmd_addnode(PayloadParser *pp)
{
uint8_t node = pp_u8(pp);
uint8_t pipenum;
bool suc = NRF_AddPipe(node, &pipenum);
if (!suc) dbg("Failed to add node.");
// TODO response
}
void respond_gw_id(void)
{
// static uint8_t buffer[MQ_SLOT_LEN];
// while (mq_read(&usb_rxq, buffer)) { // greedy - handle as many as possible
// gw_handle_usb_out(buffer);
// }
// TODO implement (after response system is added)
}
/**
* Compute the GEX network ID based on the gateway MCU unique ID.
* The ID is a 4-byte code that must be entered in each node to join the network.
*/
static void compute_network_id(void)
{
uint8_t uid[12];
PayloadBuilder pb = pb_start(uid, 12, NULL);
pb_u32(&pb, LL_GetUID_Word0());
pb_u32(&pb, LL_GetUID_Word1());
pb_u32(&pb, LL_GetUID_Word2());
uint32_t ck = CRC32_Start();
for (int i = 0; i < 12; i++) {
ck = CRC32_Add(ck, uid[i]);
}
ck = CRC32_End(ck);
pb = pb_start(gex_network, 4, NULL);
pb_u32(&pb, ck);
dbg("Dongle network ID: %02X-%02X-%02X-%02X",
gex_network[0], gex_network[1], gex_network[2], gex_network[3]);
}
void gw_setup_radio(void)
{
bool suc;
dbg("Init NRF");
NRF_Init(NRF_SPEED_2M);
compute_network_id();
NRF_SetBaseAddress(gex_network);
// TODO by config
uint8_t pipenum;
suc = NRF_AddPipe(0x01, &pipenum);
dbg("Pipe added? %d, num %d", (int)suc, (int)pipenum);
NRF_ModeRX(); // base state is RX
dbg("Send a packet");
suc = NRF_SendPacket(pipenum, (uint8_t *) "AHOJ", 5);
dbg("Suc? %d", (int)suc);
}

@ -82,7 +82,7 @@ void MX_GPIO_Init(void)
LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin);
/**/
LL_GPIO_ResetOutputPin(GPIOA, NRF_CE_Pin|NRF_NSS_Pin);
// LL_GPIO_ResetOutputPin(GPIOA, NRF_CE_Pin|NRF_NSS_Pin);
/**/
GPIO_InitStruct.Pin = LED_Pin;
@ -98,6 +98,7 @@ void MX_GPIO_Init(void)
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#if 0
/**/
LL_GPIO_AF_SetEXTISource(LL_GPIO_AF_EXTI_PORTA, LL_GPIO_AF_EXTI_LINE2);
@ -110,6 +111,7 @@ void MX_GPIO_Init(void)
/**/
LL_GPIO_SetPinMode(NRF_IRQ_GPIO_Port, NRF_IRQ_Pin, LL_GPIO_MODE_FLOATING);
#endif
}

@ -47,8 +47,6 @@
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <gex_gateway.h>
#include <msg_queue.h>
#include "main.h"
#include "stm32f1xx_hal.h"
#include "dma.h"
@ -57,6 +55,8 @@
#include "usb_device.h"
#include "gpio.h"
#include "debug.h"
#include "gex_gateway.h"
#include "msg_queue.h"
/* USER CODE BEGIN Includes */
@ -121,23 +121,21 @@ int main(void)
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
dbg("Main loop starts.");
mq_init(&usb_rxq);
mq_init(&usb_txq);
gw_setup_radio();
mq_init(&usb_inq);
dbg("Main loop starts.");
/* Infinite loop */
/* USER CODE BEGIN WHILE */
int cnt = 0;
while (1)
{
if (cnt++ > 100000) {
GPIOC->ODR ^= (1 << 13);
cnt = 0;
while (1) {
if (cnt++ > 4000000) {
LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
// GPIOC->ODR ^= (1 << 13);
cnt = 0;
}
}
gw_process();
}
/* USER CODE END 3 */
}

@ -9,8 +9,7 @@
#include "msg_queue.h"
// the two USB messaging queues
MQueue usb_rxq;
MQueue usb_txq;
MQueue usb_inq;
void mq_init(MQueue *mq)
{

@ -0,0 +1,470 @@
//
// Created by MightyPork on 2018/04/02.
//
#include <string.h>
#include "nrf.h"
#include "main.h"
#include "debug.h"
/**
* Read a register
*
* @param reg - register number (max 83)
* @return register value
*/
static uint8_t NRF_ReadRegister(uint8_t reg);
/**
* Write a register
*
* @param reg - register number (max 83)
* @param value - register value
* @return status register value
*/
static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value);
// Internal use
static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes);
static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes);
/**
* Set TX address for next frame
*
* @param SendTo - addr
*/
static void NRF_SetTxAddress(uint8_t ToAddr);
//----------------------------------------------------------
/** Tight asm loop */
#define __asm_loop(cycles) \
do { \
register uint32_t _count asm ("r4") = cycles; \
asm volatile( \
".syntax unified\n" \
".thumb\n" \
"0:" \
"subs %0, #1\n" \
"bne 0b\n" \
: "+r" (_count)); \
} while(0)
// inaccurate!
#define _delay_us(n) __asm_loop((n)*12)
static inline void CE(bool level) {
if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
}
static inline void NSS(bool level) {
if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
}
static uint8_t spi(uint8_t tx) {
while (! LL_SPI_IsActiveFlag_TXE(SPI1));
LL_SPI_TransmitData8(SPI1, tx);
while (! LL_SPI_IsActiveFlag_RXNE(SPI1));
return LL_SPI_ReceiveData8(SPI1);
}
//-------
/*
* from: http://barefootelectronics.com/NRF24L01.aspx
*/
#define CMD_READ_REG 0x00 // Read command to register
#define CMD_WRITE_REG 0x20 // Write command to register
#define CMD_RD_RX_PLD 0x61 // Read RX payload register address
#define CMD_WR_TX_PLD 0xA0 // Write TX payload register address
#define CMD_FLUSH_TX 0xE1 // Flush TX register command
#define CMD_FLUSH_RX 0xE2 // Flush RX register command
#define CMD_REUSE_TX_PL 0xE3 // Reuse TX payload register command
#define CMD_RD_RX_PL_WIDTH 0x60 // Read RX Payload Width
#define CMD_WR_ACK_PLD 0xA8 // Write ACK payload for Pipe (Add pipe number 0-6)
#define CMD_WR_TX_PLD_NK 0xB0 // Write ACK payload for not ack
#define CMD_NOP 0xFF // No Operation, might be used to read status register
// SPI(nRF24L01) registers(addresses)
#define RG_CONFIG 0x00 // 'Config' register address
#define RG_EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
#define RG_EN_RXADDR 0x02 // 'Enabled RX addresses' register address
#define RG_SETUP_AW 0x03 // 'Setup address width' register address
#define RG_SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
#define RG_RF_CH 0x05 // 'RF channel' register address
#define RG_RF_SETUP 0x06 // 'RF setup' register address
#define RG_STATUS 0x07 // 'Status' register address
#define RG_OBSERVE_TX 0x08 // 'Observe TX' register address
#define RG_CD 0x09 // 'Carrier Detect' register address
#define RG_RX_ADDR_P0 0x0A // 'RX address pipe0' register address
#define RG_RX_ADDR_P1 0x0B // 'RX address pipe1' register address
#define RG_RX_ADDR_P2 0x0C // 'RX address pipe2' register address
#define RG_RX_ADDR_P3 0x0D // 'RX address pipe3' register address
#define RG_RX_ADDR_P4 0x0E // 'RX address pipe4' register address
#define RG_RX_ADDR_P5 0x0F // 'RX address pipe5' register address
#define RG_TX_ADDR 0x10 // 'TX address' register address
#define RG_RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
#define RG_RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
#define RG_RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
#define RG_RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
#define RG_RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
#define RG_RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
#define RG_FIFO_STATUS 0x17 // 'FIFO Status Register' register address
#define RG_DYNPD 0x1C // 'Enable dynamic payload length
#define RG_FEATURE 0x1D // 'Feature register
#define RD_STATUS_TX_FULL 0x01 // tx queue full
#define RD_STATUS_RX_PNO 0x0E // pipe number of the received payload
#define RD_STATUS_MAX_RT 0x10 // max retransmissions
#define RD_STATUS_TX_DS 0x20 // data sent
#define RD_STATUS_RX_DR 0x40 // data ready
#define RD_CONFIG_PRIM_RX 0x01 // is primary receiver
#define RD_CONFIG_PWR_UP 0x02 // power up
#define RD_CONFIG_CRCO 0x04 // 2-byte CRC
#define RD_CONFIG_EN_CRC 0x08 // enable CRC
#define RD_CONFIG_DISABLE_IRQ_MAX_RT 0x10
#define RD_CONFIG_DISABLE_IRQ_TX_DS 0x20
#define RD_CONFIG_DISABLE_IRQ_RX_DR 0x40
// Config register bits (excluding the bottom two that are changed dynamically)
// enable only Rx IRQ
#define ModeBits (RD_CONFIG_DISABLE_IRQ_MAX_RT | \
RD_CONFIG_DISABLE_IRQ_TX_DS | \
RD_CONFIG_EN_CRC | \
RD_CONFIG_CRCO)
#define CEHIGH CE(1)
#define CELOW CE(0)
static inline uint8_t CS(uint8_t hl)
{
if (hl == 1) {
NSS(0);
}
else {
NSS(1);
}
return hl;
}
#define CHIPSELECT for (uint8_t cs = CS(1); cs==1; cs = CS(0))
// Base NRF address - byte 4 may be modified before writing to a pipe register,
// the first 4 bytes are shared in the network. Master is always code 0.
static uint8_t nrf_base_address[5];
static uint8_t nrf_pipe_addr[6];
static bool nrf_pipe_enabled[6];
static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value)
{
uint8_t status = 0;
CHIPSELECT {
status = spi(CMD_WRITE_REG | reg);
spi(value);
}
return status;
}
static uint8_t NRF_ReadRegister(uint8_t reg)
{
uint8_t reg_val = 0;
CHIPSELECT {
spi(CMD_READ_REG | reg);
reg_val = spi(0);
}
return reg_val;
}
static uint8_t NRF_ReadStatus(void)
{
uint8_t reg_val = 0;
CHIPSELECT {
reg_val = spi(CMD_NOP);
}
return reg_val;
}
static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes)
{
uint8_t status = 0, i = 0;
CHIPSELECT {
status = spi(CMD_WRITE_REG | reg);
for (i = 0; i < bytes; i++) {
spi(*pBuf++);
}
}
return status;
}
static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes)
{
uint8_t status = 0, i;
CHIPSELECT {
status = spi(CMD_READ_REG | reg);
for (i = 0; i < bytes; i++) {
pBuf[i] = spi(0);
}
}
return status;
}
void NRF_SetBaseAddress(const uint8_t *Bytes4)
{
memcpy(nrf_base_address, Bytes4, 4);
nrf_base_address[4] = 0;
}
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte)
{
if (pipenum > 5) {
dbg("!! bad pipe %d", pipenum);
return;
}
nrf_base_address[4] = AddrByte;
nrf_pipe_addr[pipenum] = AddrByte;
if (pipenum == 0) {
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5);
}
else if (pipenum == 1) {
NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5);
}
else {
NRF_WriteRegister(RG_RX_ADDR_P2 + (pipenum - 2), AddrByte);
}
}
bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum)
{
for (uint8_t i = 0; i < 6; i++) {
if(!nrf_pipe_enabled[i]) {
NRF_SetRxAddress(i, AddrByte);
*PipeNum = i;
NRF_EnablePipe(i);
return true;
}
}
return false;
}
uint8_t NRF_PipeNum2Addr(uint8_t pipe_num)
{
if (pipe_num > 5) return 0; // fail
return nrf_pipe_addr[pipe_num];
}
uint8_t NRF_Addr2PipeNum(uint8_t addr)
{
for (int i = 0; i < 6; i++) {
if (nrf_pipe_addr[i] == addr) return (uint8_t) i;
}
return 0xFF;
}
void NRF_EnablePipe(uint8_t pipenum)
{
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
enabled |= 1 << pipenum;
NRF_WriteRegister(RG_EN_RXADDR, enabled);
nrf_pipe_enabled[pipenum] = 1;
}
void NRF_DisablePipe(uint8_t pipenum)
{
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
enabled &= ~(1 << pipenum);
NRF_WriteRegister(RG_EN_RXADDR, enabled);
nrf_pipe_enabled[pipenum] = 0;
}
static void NRF_SetTxAddress(uint8_t SendTo)
{
nrf_base_address[4] = SendTo;
NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5);
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0
}
void NRF_PowerDown(void)
{
CELOW;
NRF_WriteRegister(RG_CONFIG, ModeBits);
}
void NRF_ModeTX(void)
{
CELOW;
uint8_t m = NRF_ReadRegister(RG_CONFIG);
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP);
if ((m & RD_CONFIG_PWR_UP) == 0) LL_mDelay(5);
}
void NRF_ModeRX(void)
{
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX);
NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception
CEHIGH;
//if ((m&2)==0) LL_mDelay()(5); You don't need to wait. Just nothing will come for 5ms or more
}
uint8_t NRF_IsModePowerDown(void)
{
uint8_t ret = 0;
if ((NRF_ReadRegister(RG_CONFIG) & RD_CONFIG_PWR_UP) == 0) ret = 1;
return ret;
}
uint8_t NRF_IsModeTX(void)
{
uint8_t m = NRF_ReadRegister(RG_CONFIG);
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
if ((m & RD_CONFIG_PRIM_RX) == 0) return 1;
return 0;
}
uint8_t NRF_IsModeRx(void)
{
uint8_t m = NRF_ReadRegister(RG_CONFIG);
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
if ((m & RD_CONFIG_PRIM_RX) == 0) return 0;
return 1;
}
void NRF_SetChannel(uint8_t Ch)
{
NRF_WriteRegister(RG_RF_CH, Ch);
}
uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum)
{
uint8_t pw = 0, status;
if (!NRF_IsRxPacket()) return 0;
CELOW;
CHIPSELECT {
status = spi(CMD_RD_RX_PL_WIDTH);
pw = spi(0);
}
if (pw > 32) {
CHIPSELECT {
spi(CMD_FLUSH_RX);
}
NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR);
return 0;
}
// Read the reception pipe number
*PipeNum = (status & RD_STATUS_RX_PNO) >> 1;
CHIPSELECT {
spi(CMD_RD_RX_PLD);
for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0);
}
NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt
CEHIGH;
return pw;
}
bool NRF_IsRxPacket(void)
{
uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR;
return 0 != ret;
}
bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length)
{
if (!nrf_pipe_enabled[PipeNum]) {
dbg("!! Pipe %d not enabled", PipeNum);
return 0;
}
const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG);
CELOW;
NRF_ModeTX(); // Make sure in TX mode
NRF_SetTxAddress(nrf_pipe_addr[PipeNum]);
CHIPSELECT {
spi(CMD_FLUSH_TX);
};
CHIPSELECT {
spi(CMD_WR_TX_PLD);
for (uint8_t i = 0; i < Length; i++) spi(Packet[i]);
};
CEHIGH;
_delay_us(15); // At least 10 us
CELOW;
uint8_t st = 0;
while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) {
st = NRF_ReadStatus(); // Packet acked or timed out
}
NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit
if ((orig_conf & RD_CONFIG_PWR_UP) == 0) {
NRF_PowerDown();
}
else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) {
NRF_ModeRX();
}
return 0 != (st & RD_STATUS_TX_DS); // success
}
void NRF_Reset(void)
{
NSS(1);
CELOW;
NRF_PowerDown();
NRF_WriteRegister(RG_EN_RXADDR, 0); // disable all pipes
for (int i = 0; i < 6; i++) {
nrf_pipe_addr[i] = 0;
nrf_pipe_enabled[i] = 0;
}
}
void NRF_Init(uint8_t pSpeed)
{
// Set the required output pins
NSS(1);
CELOW;
LL_mDelay(200);
NRF_WriteRegister(RG_CONFIG, ModeBits);
NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses
// default
// NRF_EnablePipe(0);
NRF_WriteRegister(RG_SETUP_RETR, 0x18); // 8 retries
NRF_WriteRegister(RG_RF_CH, 2); // channel 2 NO HIGHER THAN 83 in USA!
NRF_WriteRegister(RG_RF_SETUP, pSpeed);
NRF_WriteRegister(RG_DYNPD, 0b111111); // Dynamic packet length
NRF_WriteRegister(RG_FEATURE, 0b100); // Enable dynamic payload, and no payload in the ack.
for (int i = 0; i < 6; i++) {
NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length
}
//NRFModePowerDown(); // Already in power down mode, dummy
}

@ -82,7 +82,8 @@ void MX_SPI1_Init(void)
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* SPI1 DMA Init */
#if 0
/* SPI1_RX Init */
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
@ -112,6 +113,7 @@ void MX_SPI1_Init(void)
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);
#endif
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
@ -125,6 +127,7 @@ void MX_SPI1_Init(void)
SPI_InitStruct.CRCPoly = 10;
LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_SPI_Enable(SPI1);
}
/* USER CODE BEGIN 1 */

Loading…
Cancel
Save