From cf4c2d6bdad7c40e2bae2ff220e23bd5947c1919 Mon Sep 17 00:00:00 2001 From: Dhiru Kholia Date: Tue, 4 Jul 2023 21:50:49 +0530 Subject: [PATCH] feat: add nRF24L01_Wireless_F003_SOP16 TX example --- .../SPI/nRF24L01_Wireless_F003_SOP16/Makefile | 128 ++++ .../nRF24L01_Wireless_F003_SOP16/README.md | 9 + .../SPI/nRF24L01_Wireless_F003_SOP16/main.c | 178 ++++++ .../SPI/nRF24L01_Wireless_F003_SOP16/main.h | 28 + .../nRF24L01_Wireless_F003_SOP16/nrf24l01.c | 589 ++++++++++++++++++ .../nRF24L01_Wireless_F003_SOP16/nrf24l01.h | 226 +++++++ .../py32f0xx_it.c | 40 ++ .../py32f0xx_it.h | 19 + 8 files changed, 1217 insertions(+) create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/Makefile create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/README.md create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.c create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.h create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.c create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.h create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.c create mode 100644 Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.h diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/Makefile b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/Makefile new file mode 100644 index 0000000..5605b13 --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/Makefile @@ -0,0 +1,128 @@ +##### Project ##### + +PROJECT ?= app +# The path for generated files +BUILD_DIR = Build + + +##### Options ##### + +# Use LL library instead of HAL, y:yes, n:no +USE_LL_LIB ?= y +# Enable printf float %f support, y:yes, n:no +ENABLE_PRINTF_FLOAT ?= n +# Build with FreeRTOS, y:yes, n:no +USE_FREERTOS ?= n +# Build with CMSIS DSP functions, y:yes, n:no +USE_DSP ?= n +# Build with Waveshare e-paper lib, y:yes, n:no +USE_EPAPER ?= n +# Programmer, jlink or pyocd +FLASH_PROGRM ?= jlink + +##### Toolchains ####### + +#ARM_TOOCHAIN ?= /opt/gcc-arm/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin +#ARM_TOOCHAIN ?= /opt/gcc-arm/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin +ARM_TOOCHAIN ?= /opt/gcc-arm/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin + +# path to JLinkExe +JLINKEXE ?= /opt/SEGGER/JLink/JLinkExe +# JLink device type, options: +# PY32F002AX5, +# PY32F003X4, PY32F003X6, PY32F003X8, +# PY32F030X4, PY32F030X6, PY32F030X7, PY32F030X8 +JLINK_DEVICE ?= PY32F003X6 +# path to PyOCD, +PYOCD_EXE ?= pyocd +# PyOCD device type, options: +# py32f002ax5, +# py32f003x4, py32f003x6, py32f003x8, +# py32f030x3, py32f030x4, py32f030x6, py32f030x7, py32f030x8 +# py32f072xb +PYOCD_DEVICE ?= py32f003x6 + + +##### Paths ############ + +# Link descript file: py32f002ax5.ld, py32f003x6.ld, py32f003x8.ld, py32f030x6.ld, py32f030x8.ld +LDSCRIPT = Libraries/LDScripts/py32f003x6.ld +# Library build flags: +# PY32F002Ax5, +# PY32F003x4, PY32F003x6, PY32F003x8, +# PY32F030x3, PY32F030x4, PY32F030x6, PY32F030x7, PY32F030x8, +# PY32F072xB +LIB_FLAGS = PY32F003x6 + +# C source folders +CDIRS := User \ + Libraries/CMSIS/Device/PY32F0xx/Source +# C source files (if there are any single ones) +CFILES := + +# ASM source folders +ADIRS := User +# ASM single files +AFILES := Libraries/CMSIS/Device/PY32F0xx/Source/gcc/startup_py32f003.s + +# Include paths +INCLUDES := Libraries/CMSIS/Core/Include \ + Libraries/CMSIS/Device/PY32F0xx/Include \ + User + +ifeq ($(USE_LL_LIB),y) +CDIRS += Libraries/PY32F0xx_LL_Driver/Src \ + Libraries/BSP_LL/Src +INCLUDES += Libraries/PY32F0xx_LL_Driver/Inc \ + Libraries/BSP_LL/Inc +LIB_FLAGS += USE_FULL_LL_DRIVER +else +CDIRS += Libraries/PY32F0xx_HAL_Driver/Src \ + Libraries/BSP/Src +INCLUDES += Libraries/PY32F0xx_HAL_Driver/Inc \ + Libraries/BSP/Inc +endif + +ifeq ($(USE_FREERTOS),y) +CDIRS += Libraries/FreeRTOS \ + Libraries/FreeRTOS/portable/GCC/ARM_CM0 + +CFILES += Libraries/FreeRTOS/portable/MemMang/heap_4.c + +INCLUDES += Libraries/FreeRTOS/include \ + Libraries/FreeRTOS/portable/GCC/ARM_CM0 +endif + +ifeq ($(USE_DSP),y) +CFILES += Libraries/CMSIS/DSP/Source/BasicMathFunctions/BasicMathFunctions.c \ + Libraries/CMSIS/DSP/Source/BayesFunctions/BayesFunctions.c \ + Libraries/CMSIS/DSP/Source/CommonTables/CommonTables.c \ + Libraries/CMSIS/DSP/Source/ComplexMathFunctions/ComplexMathFunctions.c \ + Libraries/CMSIS/DSP/Source/ControllerFunctions/ControllerFunctions.c \ + Libraries/CMSIS/DSP/Source/DistanceFunctions/DistanceFunctions.c \ + Libraries/CMSIS/DSP/Source/FastMathFunctions/FastMathFunctions.c \ + Libraries/CMSIS/DSP/Source/FilteringFunctions/FilteringFunctions.c \ + Libraries/CMSIS/DSP/Source/InterpolationFunctions/InterpolationFunctions.c \ + Libraries/CMSIS/DSP/Source/MatrixFunctions/MatrixFunctions.c \ + Libraries/CMSIS/DSP/Source/QuaternionMathFunctions/QuaternionMathFunctions.c \ + Libraries/CMSIS/DSP/Source/StatisticsFunctions/StatisticsFunctions.c \ + Libraries/CMSIS/DSP/Source/SupportFunctions/SupportFunctions.c \ + Libraries/CMSIS/DSP/Source/SVMFunctions/SVMFunctions.c \ + Libraries/CMSIS/DSP/Source/TransformFunctions/TransformFunctions.c +INCLUDES += Libraries/CMSIS/DSP/Include \ + Libraries/CMSIS/DSP/PrivateInclude +endif + +ifeq ($(USE_EPAPER),y) +CDIRS += Libraries/EPaper/Lib \ + Libraries/EPaper/Examples \ + Libraries/EPaper/Fonts \ + Libraries/EPaper/GUI + +INCLUDES += Libraries/EPaper/Lib \ + Libraries/EPaper/Examples \ + Libraries/EPaper/Fonts \ + Libraries/EPaper/GUI +endif + +include ./rules.mk diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/README.md b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/README.md new file mode 100644 index 0000000..b07dc53 --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/README.md @@ -0,0 +1,9 @@ +Copy the `Makefile` from this folder to the root folder of this repository to +run this example on the 'PY32F003W16S6TU SOP16' chip. + +You can check that the nRF24L01+ module is transmitting by following methods: + +- Listen around 2.440 GHz using an SDR. + +- Monitor the USB in-line power meter to see that the current consumtion is + increasing during transmissions. diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.c b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.c new file mode 100644 index 0000000..419f30b --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.c @@ -0,0 +1,178 @@ +/*** + * Demo: nRF24L01 + * + * PY32 nRF24L01 + * PA0 ------> MISO + * PA1 ------> CLK/SCK + * PA4 ------> IRQ + * PA5 ------> CE + * PA6 ------> CSN + * PA7 ------> MOSI + * + * PA2 ------> TX + * PA3 ------> RX + */ +#include +#include "main.h" +#include "py32f0xx_bsp_clock.h" +#include "py32f0xx_bsp_printf.h" +#include "nrf24l01.h" + +/* Mode options: MODE_TX, MODE_RX, MODE_RX_INT */ +#define MODE_TX 0 +#define MODE_TX_FAST 1 +#define MODE_RX 2 +#define MODE_RX_INT 3 + +#define NRF24_MODE MODE_TX + +/* Payload width options: fixed or dynamic */ +#define PAYLOAD_WIDTH_MODE_FIXED 0 +#define PAYLOAD_WIDTH_MODE_DYNAMIC 1 + +#define NRF24_PAYLOAD_WIDTH_MODE PAYLOAD_WIDTH_MODE_FIXED + +#if (NRF24_MODE == MODE_TX || NRF24_MODE == MODE_TX_FAST) +uint8_t payload[] = { + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x21, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x28, + 0x31, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x38, + 0x41, 0x12, 0x13, 0x14, 0x15, 0x16, 0x47, 0x48}; +#endif + +uint8_t RX_ADDRESS[NRF24L01_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x65}; +uint8_t TX_ADDRESS[NRF24L01_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x22}; + +extern uint8_t RX_BUF[]; +extern uint8_t TX_BUF[]; + +static void APP_GPIOConfig(void); +static void APP_SPIConfig(void); + + +int main(void) +{ + /* Set clock = 8MHz */ + BSP_RCC_HSI_8MConfig(); + + /* Enable peripheral clock */ + LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA | LL_IOP_GRP1_PERIPH_GPIOB); + + BSP_USART_Config(115200); + printf("SPI Demo: nRF24L01 Wireless\r\nClock: %ld\r\n", SystemCoreClock); + + APP_GPIOConfig(); + APP_SPIConfig(); + + NRF24L01_Init(); + printf("nRF24L01 initialized\r\n"); + + while (NRF24L01_Check() != 0) + { + printf("nRF24L01 check: error\r\n"); + LL_mDelay(2000); + } + printf("nRF24L01 check: succ\r\n"); + + uint8_t length = 0; + printf("nRF24L01 in TX mode\r\n"); + NRF24L01_TX_Mode(RX_ADDRESS, TX_ADDRESS); + NRF24L01_DumpConfig(); + + while(1) + { + length = 32; + NRF24L01_TxPacket(payload, length); + LL_mDelay(5); + } +} + +uint8_t SPI_TxRxByte(uint8_t data) +{ + uint8_t SPITimeout = 0xFF; + // Check the status of Transmit buffer Empty flag + while (READ_BIT(SPI1->SR, SPI_SR_TXE) == RESET) + { + if (SPITimeout-- == 0) return 0; + } + LL_SPI_TransmitData8(SPI1, data); + SPITimeout = 0xFF; + while (READ_BIT(SPI1->SR, SPI_SR_RXNE) == RESET) + { + if (SPITimeout-- == 0) return 0; + } + // Read from RX buffer + return LL_SPI_ReceiveData8(SPI1); +} + +static void APP_GPIOConfig(void) +{ + LL_GPIO_InitTypeDef GPIO_InitStruct; + + // PA6 CSN + LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_6, LL_GPIO_MODE_OUTPUT); + // PA5 CE + LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT); + /* PA4 as input */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_4; + GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); +} + +/** + * SPI1 Alternative Function Pins + * SPI1_SCK: PA1_AF0, PA2_AF10, PA5_AF0, PA9_AF10, PB3_AF0 + * SPI1_MISO: PA0_AF10, PA6_AF0, PA7_AF10, PA11_AF0, PA13_AF10, PB4_AF0 + * SPI1_MOSI: PA1_AF10, PA2_AF0, PA3_AF10, PA7_AF0, PA8_AF10, PA12_AF0, PB5_AF0 + * SPI1_NSS: PA4_AF0, PA10_AF10, PA15_AF0, PB0_AF0, PF1_AF10, PF3_AF10 +*/ +static void APP_SPIConfig(void) +{ + LL_SPI_InitTypeDef SPI_InitStruct = {0}; + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SPI1); + + // PA1 SCK + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + GPIO_InitStruct.Alternate = LL_GPIO_AF_0; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + // PA0 MISO + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_10; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + // PA7 MOSI + GPIO_InitStruct.Pin = LL_GPIO_PIN_7; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_0; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; + SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; + SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; + SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW; + SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE; + SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; + SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4; + SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; + LL_SPI_Init(SPI1, &SPI_InitStruct); + LL_SPI_Enable(SPI1); +} + +void APP_ErrorHandler(void) +{ + while (1); +} + +#ifdef USE_FULL_ASSERT +void assert_failed(uint8_t *file, uint32_t line) +{ + while (1); +} +#endif /* USE_FULL_ASSERT */ diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.h b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.h new file mode 100644 index 0000000..d7bcace --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/main.h @@ -0,0 +1,28 @@ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "py32f0xx_ll_bus.h" +#include "py32f0xx_ll_cortex.h" +#include "py32f0xx_ll_dma.h" +#include "py32f0xx_ll_exti.h" +#include "py32f0xx_ll_gpio.h" +#include "py32f0xx_ll_pwr.h" +#include "py32f0xx_ll_rcc.h" +#include "py32f0xx_ll_spi.h" +#include "py32f0xx_ll_system.h" +#include "py32f0xx_ll_tim.h" +#include "py32f0xx_ll_utils.h" + + +void APP_ErrorHandler(void); +uint8_t SPI_TxRxByte(uint8_t data); + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.c b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.c new file mode 100644 index 0000000..c23b735 --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.c @@ -0,0 +1,589 @@ +#include +#include "nrf24l01.h" +#include "py32f0xx_bsp_printf.h" + + +uint8_t RX_BUF[NRF24L01_PLOAD_WIDTH]; +uint8_t TX_BUF[NRF24L01_PLOAD_WIDTH]; + +void NRF24L01_Init(void) +{ + CSN_HIGH; +} + +/** +* Read a 1-bit register +*/ +uint8_t NRF24L01_Read_Reg(uint8_t reg) +{ + uint8_t value; + CSN_LOW; + SPI_TxRxByte(reg); + value = SPI_TxRxByte(NRF24L01_CMD_NOP); + CSN_HIGH; + return value; +} + +/** +* Write a 1-byte register +*/ +uint8_t NRF24L01_Write_Reg(uint8_t reg, uint8_t value) +{ + uint8_t status; + CSN_LOW; + if (reg < NRF24L01_CMD_W_REGISTER) + { + // This is a register access + status = SPI_TxRxByte(NRF24L01_CMD_W_REGISTER | (reg & NRF24L01_MASK_REG_MAP)); + SPI_TxRxByte(value); + } + else + { + // This is a single byte command or future command/register + status = SPI_TxRxByte(reg); + if ((reg != NRF24L01_CMD_FLUSH_TX) + && (reg != NRF24L01_CMD_FLUSH_RX) + && (reg != NRF24L01_CMD_REUSE_TX_PL) + && (reg != NRF24L01_CMD_NOP)) { + // Send register value + SPI_TxRxByte(value); + } + } + CSN_HIGH; + return status; +} + +/** +* Read a multi-byte register +* reg - register to read +* buf - pointer to the buffer to write +* len - number of bytes to read +*/ +uint8_t NRF24L01_Read_To_Buf(uint8_t reg, uint8_t *buf, uint8_t len) +{ + CSN_LOW; + uint8_t status = SPI_TxRxByte(reg); + while (len--) + { + *buf++ = SPI_TxRxByte(NRF24L01_CMD_NOP); + } + CSN_HIGH; + return status; +} + +/** +* Write a multi-byte register +* reg - register to write +* buf - pointer to the buffer with data +* len - number of bytes to write +*/ +uint8_t NRF24L01_Write_From_Buf(uint8_t reg, const uint8_t *buf, uint8_t len) +{ + CSN_LOW; + uint8_t status = SPI_TxRxByte(reg); + while (len--) + { + SPI_TxRxByte(*buf++); + } + CSN_HIGH; + return status; +} + + +uint8_t NRF24L01_Check(void) +{ + uint8_t rxbuf[5]; + uint8_t i; + uint8_t *ptr = (uint8_t *)NRF24L01_TEST_ADDR; + + // Write test TX address and read TX_ADDR register + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_REGISTER | NRF24L01_REG_TX_ADDR, ptr, 5); + NRF24L01_Read_To_Buf(NRF24L01_CMD_R_REGISTER | NRF24L01_REG_TX_ADDR, rxbuf, 5); + + // Compare buffers, return error on first mismatch + for (i = 0; i < 5; i++) + { + if (rxbuf[i] != *ptr++) return 1; + } + return 0; +} + +/** +* Flush the RX FIFO +*/ +void NRF24L01_FlushRX(void) +{ + NRF24L01_Write_Reg(NRF24L01_CMD_FLUSH_RX, NRF24L01_CMD_NOP); +} + +/** +* Flush the TX FIFO +*/ +void NRF24L01_FlushTX(void) +{ + NRF24L01_Write_Reg(NRF24L01_CMD_FLUSH_TX, NRF24L01_CMD_NOP); +} + +void NRF24L01_ResetTX(void) +{ + NRF24L01_Write_Reg(NRF24L01_REG_STATUS, NRF24L01_FLAG_MAX_RT); // Clear max retry flag + CE_LOW; + CE_HIGH; +} + +/** +* Clear IRQ bit of the STATUS register +* reg - NRF24L01_FLAG_RX_DREADY +* NRF24L01_FLAG_TX_DSENT +* NRF24L01_FLAG_MAX_RT +*/ +void NRF24L01_ClearIRQFlag(uint8_t reg) +{ + NRF24L01_Write_Reg(NRF24L01_REG_STATUS, reg); +} + +/** +* Clear RX_DR, TX_DS and MAX_RT bits of the STATUS register +*/ +void NRF24L01_ClearIRQFlags(void) +{ + uint8_t reg; + reg = NRF24L01_Read_Reg(NRF24L01_REG_STATUS); + reg |= NRF24L01_MASK_STATUS_IRQ; + NRF24L01_Write_Reg(NRF24L01_REG_STATUS, reg); +} + +/** +* Common configurations of RX and TX, internal function +*/ +void _NRF24L01_Config(uint8_t *tx_addr) +{ + // TX Address + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_REGISTER + NRF24L01_REG_TX_ADDR, tx_addr, NRF24L01_ADDR_WIDTH); + // RX P0 Payload Width + NRF24L01_Write_Reg(NRF24L01_REG_RX_PW_P0, NRF24L01_PLOAD_WIDTH); + // Enable Auto ACK + NRF24L01_Write_Reg(NRF24L01_REG_EN_AA, 0x3f); + // Enable RX channels + NRF24L01_Write_Reg(NRF24L01_REG_EN_RXADDR, 0x3f); + // RF channel: 2.400G + 0.001 * x + NRF24L01_Write_Reg(NRF24L01_REG_RF_CH, 40); + // Format: 000+0+[0:1Mbps,1:2Mbps]+[00:-18dbm,01:-12dbm,10:-6dbm,11:0dbm]+[0:LNA_OFF,1:LNA_ON] + // 01:1Mbps,-18dbm; 03:1Mbps,-12dbm; 05:1Mbps,-6dbm; 07:1Mbps,0dBm + // 09:2Mbps,-18dbm; 0b:2Mbps,-12dbm; 0d:2Mbps,-6dbm; 0f:2Mbps,0dBm, + NRF24L01_Write_Reg(NRF24L01_REG_RF_SETUP, 0x03); + // 0A:delay=250us,count=10, 1A:delay=500us,count=10 + NRF24L01_Write_Reg(NRF24L01_REG_SETUP_RETR, 0x0a); +} + +/** +* Switch NRF24L01 to RX mode +*/ +void NRF24L01_RX_Mode(uint8_t *rx_addr, uint8_t *tx_addr) +{ + CE_LOW; + _NRF24L01_Config(tx_addr); + // RX Address of P0 + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_REGISTER + NRF24L01_REG_RX_ADDR_P0, rx_addr, NRF24L01_ADDR_WIDTH); + /** + REG 0x00: + 0)PRIM_RX 0:TX 1:RX + 1)PWR_UP 0:OFF 1:ON + 2)CRCO 0:8bit CRC 1:16bit CRC + 3)EN_CRC Enabled if any of EN_AA is high + 4)MASK_MAX_RT 0:IRQ low 1:NO IRQ + 5)MASK_TX_DS 0:IRQ low 1:NO IRQ + 6)MASK_RX_DR 0:IRQ low 1:NO IRQ + 7)Reserved 0 + */ + NRF24L01_Write_Reg(NRF24L01_REG_CONFIG, 0x0f); //RX,PWR_UP,CRC16,EN_CRC + CE_HIGH; + NRF24L01_FlushRX(); +} + +/** +* Switch NRF24L01 to TX mode +*/ +void NRF24L01_TX_Mode(uint8_t *rx_addr, uint8_t *tx_addr) +{ + CE_LOW; + _NRF24L01_Config(tx_addr); + // On the PTX the **TX_ADDR** must be the same as the **RX_ADDR_P0** and as the pipe address for the designated pipe + // RX_ADDR_P0 will be used for receiving ACK + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_REGISTER + NRF24L01_REG_RX_ADDR_P0, tx_addr, NRF24L01_ADDR_WIDTH); + NRF24L01_Write_Reg(NRF24L01_REG_CONFIG, 0x0e); //TX,PWR_UP,CRC16,EN_CRC + CE_HIGH; +} + +uint8_t NRF24L01_RX_GetPayloadWidth(void) +{ + uint8_t value; + CSN_LOW; + value = NRF24L01_Read_Reg(NRF24L01_CMD_R_RX_PL_WID); + CSN_HIGH; + return value; +} + +uint8_t NRF24L01_RXFIFO_GetStatus(void) +{ + uint8_t reg = NRF24L01_Read_Reg(NRF24L01_REG_FIFO_STATUS); + return (reg & NRF24L01_MASK_RXFIFO); +} + +uint8_t NRF24L01_ReadPayload(uint8_t *pBuf, uint8_t *length, uint8_t dpl) +{ + uint8_t status, pipe; + + // Extract a payload pipe number from the STATUS register + status = NRF24L01_Read_Reg(NRF24L01_REG_STATUS); + pipe = (status & NRF24L01_MASK_RX_P_NO) >> 1; + // RX FIFO empty? + if (pipe < 6) + { + if (dpl) + { + // Get payload width + *length = NRF24L01_RX_GetPayloadWidth(); + if (*length > 32) + { + // Error + *length = 0; + NRF24L01_FlushRX(); + } + } + else + { + *length = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P0 + pipe); + } + // Read a payload from the RX FIFO + if (*length) + { + NRF24L01_Read_To_Buf(NRF24L01_CMD_R_RX_PAYLOAD, pBuf, *length); + } + return pipe; + } + // pipe value = 110: Not Used, 111: RX FIFO Empty + *length = 0; + return pipe; +} + +/** +* Send data in tx_buf and wait till data is sent or max re-tr reached +*/ +uint8_t NRF24L01_TxPacket(uint8_t *tx_buf, uint8_t len) +{ + uint8_t status = 0x00; + CE_LOW; + len = len > NRF24L01_PLOAD_WIDTH? NRF24L01_PLOAD_WIDTH : len; + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_TX_PAYLOAD, tx_buf, len); + CE_HIGH; + while(IRQ != 0); // Waiting send finish + + CE_LOW; + status = NRF24L01_Read_Reg(NRF24L01_REG_STATUS); + BSP_UART_TxHex8(status); + BSP_UART_TxChar(':'); + if(status & NRF24L01_FLAG_TX_DS) + { + BSP_UART_TxString("Data sent: "); + for (uint8_t i = 0; i < len; i++) { + BSP_UART_TxHex8(tx_buf[i]); + } + BSP_UART_TxString("\r\n"); + NRF24L01_ClearIRQFlag(NRF24L01_FLAG_TX_DS); + } + else if(status & NRF24L01_FLAG_MAX_RT) + { + BSP_UART_TxString("Sending exceeds max retries\r\n"); + NRF24L01_FlushTX(); + NRF24L01_ClearIRQFlag(NRF24L01_FLAG_MAX_RT); + } + CE_HIGH; + return status; +} + +void NRF24L01_TxPacketFast(const void *pBuf, uint8_t len) +{ + NRF24L01_Write_From_Buf(NRF24L01_CMD_W_TX_PAYLOAD, pBuf, len); + CE_HIGH; +} + +uint8_t NRF24L01_TxFast(const void *pBuf, uint8_t len) +{ + uint8_t status; + // Blocking only if FIFO is full. This will loop and block until TX is successful or fail + do + { + status = NRF24L01_Read_Reg(NRF24L01_REG_STATUS); + if (status & NRF24L01_FLAG_MAX_RT) + { + return 1; + } + + } while (status & NRF24L01_FLAG_TX_FULL); + NRF24L01_TxPacketFast(pBuf, len); + return 0; +} + +void NRF24L01_ToggleFeatures(void) +{ + CSN_LOW; + NRF24L01_Write_Reg(NRF24L01_CMD_ACTIVATE, 0x73); + CSN_HIGH; +} + +void NRF24L01_SetEnableDynamicPayloads(uint8_t mode) +{ + uint8_t reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if (mode == 0) + { + // Disable dynamic payload throughout the system + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg & (~NRF24L01_FEATURE_EN_DPL)); + // If it didn't work, the features are not enabled + reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if ((reg & NRF24L01_FEATURE_EN_DPL) != 0) + { + // Enable them and try again + NRF24L01_ToggleFeatures(); + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg & (~NRF24L01_FEATURE_EN_DPL)); + } + // Disable dynamic payload on all pipes + NRF24L01_Write_Reg(NRF24L01_REG_DYNPD, 0); + } + else + { + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg | NRF24L01_FEATURE_EN_DPL); + reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if ((reg & NRF24L01_FEATURE_EN_DPL) != NRF24L01_FEATURE_EN_DPL) + { + NRF24L01_ToggleFeatures(); + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg | NRF24L01_FEATURE_EN_DPL); + } + // Enable dynamic payload on all pipes + NRF24L01_Write_Reg(NRF24L01_REG_DYNPD, NRF24L01_DYNPD_DPL_P0 | NRF24L01_DYNPD_DPL_P1 + | NRF24L01_DYNPD_DPL_P2 | NRF24L01_DYNPD_DPL_P3 | NRF24L01_DYNPD_DPL_P4 | NRF24L01_DYNPD_DPL_P5); + } + +} + +void NRF24L01_SetEnableAckPayload(uint8_t mode) +{ + uint8_t reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if (mode == 0) + { + // Disable ack payload and dynamic payload features + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg &(~NRF24L01_FEATURE_EN_ACK_PAY)); + // If it didn't work, the features are not enabled + reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if ((reg & NRF24L01_FEATURE_EN_ACK_PAY) != NRF24L01_FEATURE_EN_ACK_PAY) + { + // Enable them and try again + NRF24L01_ToggleFeatures(); + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg &(~NRF24L01_FEATURE_EN_ACK_PAY)); + } + } + else + { + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg | NRF24L01_FEATURE_EN_ACK_PAY); + reg = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + if ((reg & NRF24L01_FEATURE_EN_ACK_PAY) != NRF24L01_FEATURE_EN_ACK_PAY) + { + NRF24L01_ToggleFeatures(); + NRF24L01_Write_Reg(NRF24L01_REG_FEATURE, reg | NRF24L01_FEATURE_EN_ACK_PAY); + } + // Enable dynamic payload on pipes 0 & 1 + reg = NRF24L01_Read_Reg(NRF24L01_REG_DYNPD); + NRF24L01_Write_Reg(NRF24L01_REG_DYNPD, reg | NRF24L01_DYNPD_DPL_P0 | NRF24L01_DYNPD_DPL_P1); + } +} + +/** +* Dump nRF24L01 configuration +*/ +void NRF24L01_DumpConfig(void) { + uint8_t i,j; + uint8_t aw; + uint8_t buf[5]; + + // CONFIG + i = NRF24L01_Read_Reg(NRF24L01_REG_CONFIG); + printf("[0x%02X] 0x%02X MASK:%02X CRC:%02X PWR:%s MODE:P%s\r\n", + NRF24L01_REG_CONFIG, + i, + i >> 4, + (i & 0x0c) >> 2, + (i & 0x02) ? "ON" : "OFF", + (i & 0x01) ? "RX" : "TX" + ); + // EN_AA + i = NRF24L01_Read_Reg(NRF24L01_REG_EN_AA); + printf("[0x%02X] 0x%02X ENAA: ",NRF24L01_REG_EN_AA,i); + for (j = 0; j < 6; j++) { + printf("[P%1u%s]%s",j, + (i & (1 << j)) ? "+" : "-", + (j == 5) ? "\r\n" : " " + ); + } + // EN_RXADDR + i = NRF24L01_Read_Reg(NRF24L01_REG_EN_RXADDR); + printf("[0x%02X] 0x%02X EN_RXADDR: ",NRF24L01_REG_EN_RXADDR,i); + for (j = 0; j < 6; j++) { + printf("[P%1u%s]%s",j, + (i & (1 << j)) ? "+" : "-", + (j == 5) ? "\r\n" : " " + ); + } + // SETUP_AW + i = NRF24L01_Read_Reg(NRF24L01_REG_SETUP_AW); + aw = (i & 0x03) + 2; + printf("[0x%02X] 0x%02X EN_RXADDR=%03X (address width = %u)\r\n",NRF24L01_REG_SETUP_AW,i,i & 0x03,aw); + // SETUP_RETR + i = NRF24L01_Read_Reg(NRF24L01_REG_SETUP_RETR); + printf("[0x%02X] 0x%02X ARD=%04X ARC=%04X (retr.delay=%uus, count=%u)\r\n", + NRF24L01_REG_SETUP_RETR, + i, + i >> 4, + i & 0x0F, + ((i >> 4) * 250) + 250, + i & 0x0F + ); + // RF_CH + i = NRF24L01_Read_Reg(NRF24L01_REG_RF_CH); + printf("[0x%02X] 0x%02X (%.3uGHz)\r\n",NRF24L01_REG_RF_CH,i,2400 + i); + // RF_SETUP + i = NRF24L01_Read_Reg(NRF24L01_REG_RF_SETUP); + printf("[0x%02X] 0x%02X CONT_WAVE:%s PLL_LOCK:%s DataRate=", + NRF24L01_REG_RF_SETUP, + i, + (i & 0x80) ? "ON" : "OFF", + (i & 0x80) ? "ON" : "OFF" + ); + switch ((i & 0x28) >> 3) { + case 0x00: + printf("1M"); + break; + case 0x01: + printf("2M"); + break; + case 0x04: + printf("250k"); + break; + default: + printf("???"); + break; + } + printf("pbs RF_PWR="); + switch ((i & 0x06) >> 1) { + case 0x00: + printf("-18"); + break; + case 0x01: + printf("-12"); + break; + case 0x02: + printf("-6"); + break; + case 0x03: + printf("0"); + break; + default: + printf("???"); + break; + } + printf("dBm\r\n"); + // STATUS + i = NRF24L01_Read_Reg(NRF24L01_REG_STATUS); + printf("[0x%02X] 0x%02X IRQ:%03X RX_PIPE:%u TX_FULL:%s\r\n", + NRF24L01_REG_STATUS, + i, + (i & 0x70) >> 4, + (i & 0x0E) >> 1, + (i & 0x01) ? "YES" : "NO" + ); + + // OBSERVE_TX + i = NRF24L01_Read_Reg(NRF24L01_REG_OBSERVE_TX); + printf("[0x%02X] 0x%02X PLOS_CNT=%u ARC_CNT=%u\r\n",NRF24L01_REG_OBSERVE_TX,i,i >> 4,i & 0x0F); + + // RPD + i = NRF24L01_Read_Reg(NRF24L01_REG_RPD); + printf("[0x%02X] 0x%02X RPD=%s\r\n",NRF24L01_REG_RPD,i,(i & 0x01) ? "YES" : "NO"); + + // RX_ADDR_P0 + NRF24L01_Read_To_Buf(NRF24L01_REG_RX_ADDR_P0,buf,aw); + printf("[0x%02X] RX_ADDR_P0 \"",NRF24L01_REG_RX_ADDR_P0); + for (i = 0; i < aw; i++) printf("%X ",buf[i]); + printf("\"\r\n"); + + // RX_ADDR_P1 + NRF24L01_Read_To_Buf(NRF24L01_REG_RX_ADDR_P1,buf,aw); + printf("[0x%02X] RX_ADDR_P1 \"",NRF24L01_REG_RX_ADDR_P1); + for (i = 0; i < aw; i++) printf("%X ",buf[i]); + printf("\"\r\n"); + + // RX_ADDR_P2 + printf("[0x%02X] RX_ADDR_P2 \"",NRF24L01_REG_RX_ADDR_P2); + for (i = 0; i < aw - 1; i++) printf("%X ",buf[i]); + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_ADDR_P2); + printf("%X\"\r\n",i); + + // RX_ADDR_P3 + printf("[0x%02X] RX_ADDR_P3 \"",NRF24L01_REG_RX_ADDR_P3); + for (i = 0; i < aw - 1; i++) printf("%X ",buf[i]); + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_ADDR_P3); + printf("%X\"\r\n",i); + + // RX_ADDR_P4 + printf("[0x%02X] RX_ADDR_P4 \"",NRF24L01_REG_RX_ADDR_P4); + for (i = 0; i < aw - 1; i++) printf("%X ",buf[i]); + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_ADDR_P4); + printf("%X\"\r\n",i); + + // RX_ADDR_P5 + printf("[0x%02X] RX_ADDR_P5 \"",NRF24L01_REG_RX_ADDR_P5); + for (i = 0; i < aw - 1; i++) printf("%X ",buf[i]); + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_ADDR_P5); + printf("%X\"\r\n",i); + + // TX_ADDR + NRF24L01_Read_To_Buf(NRF24L01_REG_TX_ADDR,buf,aw); + printf("[0x%02X] TX_ADDR \"",NRF24L01_REG_TX_ADDR); + for (i = 0; i < aw; i++) printf("%X ",buf[i]); + printf("\"\r\n"); + + // RX_PW_P0 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P0); + printf("[0x%02X] RX_PW_P0=%u\r\n",NRF24L01_REG_RX_PW_P0,i); + + // RX_PW_P1 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P1); + printf("[0x%02X] RX_PW_P1=%u\r\n",NRF24L01_REG_RX_PW_P1,i); + + // RX_PW_P2 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P2); + printf("[0x%02X] RX_PW_P2=%u\r\n",NRF24L01_REG_RX_PW_P2,i); + + // RX_PW_P3 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P3); + printf("[0x%02X] RX_PW_P3=%u\r\n",NRF24L01_REG_RX_PW_P3,i); + + // RX_PW_P4 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P4); + printf("[0x%02X] RX_PW_P4=%u\r\n",NRF24L01_REG_RX_PW_P4,i); + + // RX_PW_P5 + i = NRF24L01_Read_Reg(NRF24L01_REG_RX_PW_P5); + printf("[0x%02X] RX_PW_P5=%u\r\n",NRF24L01_REG_RX_PW_P5,i); + + // NRF24L01_REG_FIFO_STATUS + i = NRF24L01_Read_Reg(NRF24L01_REG_FIFO_STATUS); + printf("[0x%02X] FIFO_STATUS=0x%02x\r\n",NRF24L01_REG_FIFO_STATUS,i); + + // NRF24L01_REG_DYNPD + i = NRF24L01_Read_Reg(NRF24L01_REG_DYNPD); + printf("[0x%02X] DYNPD=0x%02x\r\n",NRF24L01_REG_DYNPD,i); + + // NRF24L01_REG_FEATURE + i = NRF24L01_Read_Reg(NRF24L01_REG_FEATURE); + printf("[0x%02X] FEATURE=0x%02x\r\n",NRF24L01_REG_FEATURE,i); +} diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.h b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.h new file mode 100644 index 0000000..0c74d5f --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/nrf24l01.h @@ -0,0 +1,226 @@ +#ifndef _NRF24L01_H +#define _NRF24L01_H + +#include + +// CE Pin & CSN Pin & IRQ Pin +#define CSN_HIGH LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_6) +#define CSN_LOW LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_6) +#define CE_HIGH LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5) +#define CE_LOW LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5) +#define IRQ READ_BIT(GPIOA->IDR, LL_GPIO_PIN_4) + +// SPI(nRF24L01) commands +#define NRF24L01_CMD_R_REGISTER 0x00 // Register read +#define NRF24L01_CMD_W_REGISTER 0x20 // Register write +/** + * ACTIVATE. For NRF24L01 only, removed from NRF24L01+ product specs + * - https://github.com/nRF24/RF24/issues/401 + * + * This write command followed by data 0x73 activates the following features: R_RX_PL_WID, W_ACK_PAYLOAD, W_TX_PAYLOAD_NOACK. + * A new ACTIVATE command with the same data deactivates them again. This is executable in power down or stand by modes only. +*/ +#define NRF24L01_CMD_ACTIVATE 0x50 // (De)Activates R_RX_PL_WID, W_ACK_PAYLOAD, W_TX_PAYLOAD_NOACK features +#define NRF24L01_CMD_R_RX_PL_WID 0x60 // Read RX-payload width for the top R_RX_PAYLOAD in the RX FIFO. Flush RX FIFO if the read value is larger than 32 bytes +#define NRF24L01_CMD_R_RX_PAYLOAD 0x61 // Read RX payload +#define NRF24L01_CMD_W_TX_PAYLOAD 0xA0 // Write TX payload +#define NRF24L01_CMD_W_ACK_PAYLOAD 0xA8 // 1010 1PPP, Used in RX mode. Write Payload to be transmitted together with ACK packet on PIPE PPP. (PPP valid in the range from 000 to 101) +#define NRF24L01_CMD_W_TX_PAYLOAD_NOACK 0xB0 // Used in TX mode. Disables AUTOACK on this specific packet +#define NRF24L01_CMD_FLUSH_TX 0xE1 // Flush TX FIFO +#define NRF24L01_CMD_FLUSH_RX 0xE2 // Flush RX FIFO +#define NRF24L01_CMD_REUSE_TX_PL 0xE3 // Reuse TX payload +#define NRF24L01_CMD_LOCK_UNLOCK 0x50 // Lock/unlock exclusive features +#define NRF24L01_CMD_NOP 0xFF // No operation (used for reading status register) + +// SPI(nRF24L01) register address definitions +#define NRF24L01_REG_CONFIG 0x00 // Configuration register +#define NRF24L01_REG_EN_AA 0x01 // Enable "Auto acknowledgment" +#define NRF24L01_REG_EN_RXADDR 0x02 // Enable RX addresses +#define NRF24L01_REG_SETUP_AW 0x03 // Setup of address widths +#define NRF24L01_REG_SETUP_RETR 0x04 // Setup of automatic re-transmit +#define NRF24L01_REG_RF_CH 0x05 // RF channel +#define NRF24L01_REG_RF_SETUP 0x06 // RF setup +#define NRF24L01_REG_STATUS 0x07 // Status register +#define NRF24L01_REG_OBSERVE_TX 0x08 // Transmit observe register +#define NRF24L01_REG_RPD 0x09 // Received power detector +#define NRF24L01_REG_RX_ADDR_P0 0x0A // Receive address data pipe 0 +#define NRF24L01_REG_RX_ADDR_P1 0x0B // Receive address data pipe 1 +#define NRF24L01_REG_RX_ADDR_P2 0x0C // Receive address data pipe 2 +#define NRF24L01_REG_RX_ADDR_P3 0x0D // Receive address data pipe 3 +#define NRF24L01_REG_RX_ADDR_P4 0x0E // Receive address data pipe 4 +#define NRF24L01_REG_RX_ADDR_P5 0x0F // Receive address data pipe 5 +#define NRF24L01_REG_TX_ADDR 0x10 // Transmit address +#define NRF24L01_REG_RX_PW_P0 0x11 // Number of bytes in RX payload in data pipe 0 +#define NRF24L01_REG_RX_PW_P1 0x12 // Number of bytes in RX payload in data pipe 1 +#define NRF24L01_REG_RX_PW_P2 0x13 // Number of bytes in RX payload in data pipe 2 +#define NRF24L01_REG_RX_PW_P3 0x14 // Number of bytes in RX payload in data pipe 3 +#define NRF24L01_REG_RX_PW_P4 0x15 // Number of bytes in RX payload in data pipe 4 +#define NRF24L01_REG_RX_PW_P5 0x16 // Number of bytes in RX payload in data pipe 5 +#define NRF24L01_REG_FIFO_STATUS 0x17 // FIFO status register +#define NRF24L01_REG_DYNPD 0x1C // Enable dynamic payload length +#define NRF24L01_REG_FEATURE 0x1D // Feature register + +// Register bits definitions +#define NRF24L01_CONFIG_PRIM_RX 0x01 // PRIM_RX bit in CONFIG register +#define NRF24L01_CONFIG_PWR_UP 0x02 // PWR_UP bit in CONFIG register + +// Enable dynamic payload length on data pipes +#define NRF24L01_DYNPD_DPL_P5 0x20 +#define NRF24L01_DYNPD_DPL_P4 0x10 +#define NRF24L01_DYNPD_DPL_P3 0x08 +#define NRF24L01_DYNPD_DPL_P2 0x04 +#define NRF24L01_DYNPD_DPL_P1 0x02 +#define NRF24L01_DYNPD_DPL_P0 0x01 + +/** + * EN_DYN_ACK - this bit enables the W_TX_PAYLOAD_NOACK command + * + * The PTX can set the NO_ACK flag bit in the Packet Control Field with this command: W_TX_PAYLOAD_NOACK + * However, the function must first be enabled in the FEATURE register by setting the EN_DYN_ACK bit. + * When you use this option the PTX goes directly to standby-I mode after transmitting the packet. The PRX + * does not transmit an ACK packet when it receives the packet. +*/ +#define NRF24L01_FEATURE_EN_DYN_ACK 0x01 // EN_DYN_ACK bit in FEATURE register +/** + * EN_ACK_PAY - Enables Payload with ACK + * If ACK packet payload is activated, ACK packets have dynamic payload lengths and the Dynamic Payload + * Length feature should be enabled for pipe 0 on the PTX and PRX. This is to ensure that they receive the + * ACK packets with payloads. If the ACK payload is more than 15 byte in 2Mbps mode the ARD must be + * 500µS or more, and if the ACK payload is more than 5 byte in 1Mbps mode the ARD must be 500µS or + * more. In 250kbps mode (even when the payload is not in ACK) the ARD must be 500µS or more. +*/ +#define NRF24L01_FEATURE_EN_ACK_PAY 0x02 // EN_ACK_PAY bit in FEATURE register +#define NRF24L01_FEATURE_EN_DPL 0x04 // EN_DPL bit in FEATURE register, enables Dynamic Payload Length + +// Status Flags +#define NRF24L01_FLAG_RX_DR 0x40 // RX_DR bit (data ready RX FIFO interrupt) +#define NRF24L01_FLAG_TX_DS 0x20 // TX_DS bit (data sent TX FIFO interrupt) +#define NRF24L01_FLAG_MAX_RT 0x10 // MAX_RT bit (maximum number of TX re-transmits interrupt) +#define NRF24L01_FLAG_IT_BITS 0x70 // RX_DR|TX_DS|MAX_RT +#define NRF24L01_FLAG_TX_FULL 0x01 // TX FIFO full flag. 1: TX FIFO full. 0: Available locations in TX FIFO + +// Register masks definitions +#define NRF24L01_MASK_REG_MAP 0x1F // Mask bits[4:0] for CMD_RREG and CMD_WREG commands +#define NRF24L01_MASK_CRC 0x0C // Mask for CRC bits [3:2] in CONFIG register +#define NRF24L01_MASK_STATUS_IRQ 0x70 // Mask for all IRQ bits in STATUS register +#define NRF24L01_MASK_RF_PWR 0x06 // Mask RF_PWR[2:1] bits in RF_SETUP register +#define NRF24L01_MASK_RX_P_NO 0x0E // Mask RX_P_NO[3:1] bits in STATUS register +#define NRF24L01_MASK_DATARATE 0x28 // Mask RD_DR_[5,3] bits in RF_SETUP register +#define NRF24L01_MASK_EN_RX 0x3F // Mask ERX_P[5:0] bits in EN_RXADDR register +#define NRF24L01_MASK_RX_PW 0x3F // Mask [5:0] bits in RX_PW_Px register +#define NRF24L01_MASK_RETR_ARD 0xF0 // Mask for ARD[7:4] bits in SETUP_RETR register +#define NRF24L01_MASK_RETR_ARC 0x0F // Mask for ARC[3:0] bits in SETUP_RETR register +#define NRF24L01_MASK_RXFIFO 0x03 // Mask for RX FIFO status bits [1:0] in FIFO_STATUS register +#define NRF24L01_MASK_TXFIFO 0x30 // Mask for TX FIFO status bits [5:4] in FIFO_STATUS register +#define NRF24L01_MASK_PLOS_CNT 0xF0 // Mask for PLOS_CNT[7:4] bits in OBSERVE_TX register +#define NRF24L01_MASK_ARC_CNT 0x0F // Mask for ARC_CNT[3:0] bits in OBSERVE_TX register + +// Register masks definitions +#define NRF24L01_MASK_REG_MAP 0x1F // Mask bits[4:0] for CMD_RREG and CMD_WREG commands + +// RXFIFO status +#define NRF24L01_RXFIFO_STATUS_DATA 0x00 // The RX FIFO contains data and available locations +#define NRF24L01_RXFIFO_STATUS_EMPTY 0x01 // The RX FIFO is empty +#define NRF24L01_RXFIFO_STATUS_FULL 0x02 // The RX FIFO is full +#define NRF24L01_RXFIFO_STATUS_ERROR 0x03 // Impossible state: RX FIFO cannot be empty and full at the same time + +#define NRF24L01_ADDR_WIDTH 5 // RX/TX address width +#define NRF24L01_PLOAD_WIDTH 32 // Payload width +#define NRF24L01_TEST_ADDR "nRF24" + +void NRF24L01_Init(void); + +uint8_t NRF24L01_Check(void); + +/** +* Dump nRF24L01+ configuration +*/ +void NRF24L01_DumpConfig(void); + +/** +* Read a 1-bit register +*/ +uint8_t NRF24L01_Read_Reg(uint8_t reg); + +/** +* Write a 1-byte register +*/ +uint8_t NRF24L01_Write_Reg(uint8_t reg,uint8_t value); + +/** +* Read a multi-byte register +* reg - register to read +* buf - pointer to the buffer to write +* len - number of bytes to read +*/ +uint8_t NRF24L01_Read_To_Buf(uint8_t reg,uint8_t *pBuf,uint8_t len); + +/** +* Write a multi-byte register +* reg - register to write +* buf - pointer to the buffer with data +* len - number of bytes to write +*/ +uint8_t NRF24L01_Write_From_Buf(uint8_t reg, const uint8_t *pBuf,uint8_t len); + +void NRF24L01_SetEnableDynamicPayloads(uint8_t mode); + +void NRF24L01_SetEnableAckPayload(uint8_t mode); + +/** + * Get status of the RX FIFO +*/ +uint8_t NRF24L01_RXFIFO_GetStatus(void); + +/** + * Read received data (no fifo status check, no status clear, just read) +*/ +uint8_t NRF24L01_ReadPayload(uint8_t *pBuf, uint8_t *length, uint8_t dpl); + +/** +* Send data in tx_buf and wait till data is sent or max re-tr reached +*/ +uint8_t NRF24L01_TxPacket(uint8_t *tx_buf, uint8_t len); + +/** + * Send data in FIFO without sync ack +*/ +uint8_t NRF24L01_TxFast(const void *pBuf, uint8_t len); + +/** +* Switch NRF24L01 to RX mode +*/ +void NRF24L01_RX_Mode(uint8_t *rx_addr, uint8_t *tx_addr); + +/** +* Switch NRF24L01 to TX mode +*/ +void NRF24L01_TX_Mode(uint8_t *rx_addr, uint8_t *tx_addr); + +/** +* Flush the RX FIFO +*/ +void NRF24L01_FlushRX(void); + +/** +* Flush the TX FIFO +*/ +void NRF24L01_FlushTX(void); + +/** + * Clear TX error flags +*/ +void NRF24L01_ResetTX(void); + +/** +* Clear IRQ bit of the STATUS register +* reg - NRF24L01_FLAG_RX_DREADY, NRF24L01_FLAG_TX_DSENT, NRF24L01_FLAG_MAX_RT +*/ +void NRF24L01_ClearIRQFlag(uint8_t reg); + +/** +* Clear RX_DR, TX_DS and MAX_RT bits of the STATUS register +*/ +void NRF24L01_ClearIRQFlags(void); + +#endif /*_NRF24L01_H*/ diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.c b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.c new file mode 100644 index 0000000..3a10d14 --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.c @@ -0,0 +1,40 @@ +#include "main.h" +#include "py32f0xx_it.h" + +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ +} diff --git a/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.h b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.h new file mode 100644 index 0000000..76b3dad --- /dev/null +++ b/Examples/LL/SPI/nRF24L01_Wireless_F003_SOP16/py32f0xx_it.h @@ -0,0 +1,19 @@ +#ifndef __PY32F0XX_IT_H +#define __PY32F0XX_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void NMI_Handler(void); +void HardFault_Handler(void); +void SVC_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __PY32F0XX_IT_H */