一、使用方法:
- 使用STM32CubeIDE 的STM32CubeMX工具設定SPI pin。
- 將nRF24L01.c複製到src資料夾,nRF24L01.h複製到inc資料夾下。
- 覆寫__weak function (IRQ callback)
__weak void nRF24_irq_callback(uint8_t event_type, uint16_t data_src, uint8_t* data, uint8_t width)參數:
event_type:EVENT_RX_DR為nRF24L01接收資料時處理程序。
EVENT_TX_RS為送完資料成功收到ACK時處理程序。
EVENT_MAX_RT為達到重送最大值時處理程序。
EVENT_GPIO_IRQ為非nRF24L01的其他GPIO IRQ處理程序。
data_src: 接收資料時的datapipe,不是nRF24L01的interrupt時,為其他GPIO interrupt 的GPIO pin number。
data:收取資料的內容。
width:data的長度。 - Driver initialize:nRF24_spi_init(&hspi1, MX_nRF24_CSn_GPIO_Port, MX_nRF24_CSn_Pin, MX_nRF24_CE_GPIO_Port, MX_nRF24_CE_Pin,MX_nRF24_IRQ_GPIO_Port, MX_nRF24_IRQ_Pin);
- 指定為Transmitter or Receiver:
nRF24_config_mode(role); 1:Receiver, 0:transmitter。 - enable Feature:
nRF24_enable_feature(FEATURE_EN_DPL, 1); - 指定位址:nRF24_set_RX_addr(0, address, 5);nRF24_set_TX_addr(address, 5);
- 設定datapipe 啟用dynamic payload length:
nRF24_enable_data_pipe_dynamic_payload_length(0, 1);// 1: enable, 0:disable - Transmitter傳送payload:
nRF24_write_payload(payload, lenght);
二、範例
下列範例為Receiver收到payload後,轉換成Transmitter傳送payload至其他node:
展示影片:
- main.c
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "nRF24L01.h" #include "string.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ SPI_HandleTypeDef hspi1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_SPI1_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ //#define nRF24_RECEIVER uint8_t can_send=0; uint8_t send_buffer[33]; uint8_t addr[6][5] = {"0node", "1node", "2node","3node","4node","5node"}; uint8_t transnode=1; uint8_t total_nodes=4; uint8_t send_buffer[33]; uint8_t role, new_role; void nRF24_irq_callback(uint8_t event_type, uint16_t data_src, uint8_t* data, uint8_t width) { switch(event_type) { case EVENT_RX_DR: HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); can_send=1; new_role = TRANSMITTER; break; case EVENT_TX_DS: HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); new_role=RECEIVER; can_send=0; break; case EVENT_MAX_RT: break; case EVENT_GPIO_IRQ: break; } } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); /* USER CODE BEGIN 2 */ role = RECEIVER; new_role=role; nRF24_spi_init(&hspi1, MX_nRF24_CSn_GPIO_Port, MX_nRF24_CSn_Pin, MX_nRF24_CE_GPIO_Port, MX_nRF24_CE_Pin, MX_nRF24_IRQ_GPIO_Port, MX_nRF24_IRQ_Pin); nRF24_enable_feature(FEATURE_EN_DPL, 1); nRF24_config_mode(role); nRF24_enable_RXADDR(0b00000011); nRF24_set_RX_addr(0, addr[(transnode+1)%total_nodes], 5); nRF24_set_TX_addr(addr[(transnode+1)%total_nodes], 5); nRF24_set_RX_addr(1, addr[transnode], 5); nRF24_enable_data_pipe_dynamic_payload_length(0, 1); nRF24_enable_data_pipe_dynamic_payload_length(1, 1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ int count=0; while (1) { if (role != new_role) { role = new_role; nRF24_config_mode(role); } if (can_send && role==TRANSMITTER) { can_send=0; sprintf((char*)send_buffer, "0:abcdefgh%d", count++); count %=10000; nRF24_write_payload(send_buffer,strlen((char*)send_buffer)); } HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /** * @brief SPI1 Initialization Function * @param None * @retval None */ static void MX_SPI1_Init(void) { /* USER CODE BEGIN SPI1_Init 0 */ /* USER CODE END SPI1_Init 0 */ /* USER CODE BEGIN SPI1_Init 1 */ /* USER CODE END SPI1_Init 1 */ /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN SPI1_Init 2 */ /* USER CODE END SPI1_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, MX_nRF24_CE_Pin|MX_nRF24_CSn_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : LED_Pin */ GPIO_InitStruct.Pin = LED_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : MX_nRF24_IRQ_Pin */ GPIO_InitStruct.Pin = MX_nRF24_IRQ_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(MX_nRF24_IRQ_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pins : MX_nRF24_CE_Pin MX_nRF24_CSn_Pin */ GPIO_InitStruct.Pin = MX_nRF24_CE_Pin|MX_nRF24_CSn_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI2_IRQn); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */
三、驅動程式碼:
- nRF24L01.c
#include <stdio.h> #include "string.h" #include "main.h" #include "nRF24L01.h" // SPI Defines static SPI_HandleTypeDef* nRF24_SPI; static GPIO_TypeDef* nRF24_GPIO_CE_port=GPIOB; static GPIO_TypeDef* nRF24_GPIO_CSn_port=GPIOB; static GPIO_TypeDef* nRF24_GPIO_IRQ_port=GPIOB; static uint16_t nRF24_GPIO_CE_pin=GPIO_PIN_6; static uint16_t nRF24_GPIO_CSn_pin=GPIO_PIN_7; static uint16_t nRF24_GPIO_IRQ_pin=GPIO_PIN_8; static uint32_t nRF24_SPI_TIMEOUT=1000; //nRF24_irq_callback_t nRF24_callback; static uint8_t nRF24_data_buffer[64]; static void nRF24_standby_to_txrx_mode(); static void nRF24_standby_I(); static void nRF24_reset_REGISTER(); static void nRF24_spi_enable(); static void nRF24_spi_disable(); /*! * \brief STM32 GPIO IRQ Callback * nRF24L01 IRQ callback function * \param gpio: gpio number */ void HAL_GPIO_EXTI_Callback(uint16_t gpio) { uint8_t status; uint8_t event_type; uint16_t data_src; uint8_t width=0; memset(nRF24_data_buffer,0, 32); if (gpio == nRF24_GPIO_IRQ_pin) { nRF24_status(&status); data_src = (status & 0x0E) >> 1; if ((status & 0x40) >> EVENT_RX_DR) { // RX_DR event_type = EVENT_RX_DR; if (nRF24_get_RX_payload_width(&width) == HAL_OK) { if (width > 32) { // in nRF24L01+ product specification printf("...in driver width > 32 datapipe:%d:%d\n", data_src, width); nRF24_standby_I(); nRF24_flush_rx(); // nRF24_standby_to_txrx_mode(); } else { nRF24_read_payload(nRF24_data_buffer, width); nRF24_irq_callback(event_type, data_src, nRF24_data_buffer, width); } nRF24_clear_RX_DR(); } } if ((status & 0x20) >> EVENT_TX_DS) { // TX_DS event_type = EVENT_TX_DS; nRF24_irq_callback(event_type, data_src, nRF24_data_buffer, 0); nRF24_clear_TX_DS(); } if ((status & 0x10) >> EVENT_MAX_RT) { // MAX_RT event_type = EVENT_MAX_RT; nRF24_irq_callback(event_type, data_src, nRF24_data_buffer, 0); nRF24_clear_MAX_RT(); } } else { event_type = EVENT_GPIO_IRQ; // STM32 gpio irq except nRF24L01 IRQ nRF24_irq_callback(event_type, gpio, nRF24_data_buffer, width); } } /*! * \brief set nRF24L01 PWR_UP in CONFIG register */ static void nRF24_config_PWR_UP() { uint8_t ret; uint8_t mode; ret = nRF24_read_REGISTER(CONFIG, &mode,1); if (ret == HAL_OK) { mode |= (0x02); ret = nRF24_write_REGISTER(CONFIG, &mode,1); } } /*! * \brief enable CE, set CE high */ static void nRF24_enable_CE() { //gpio_put(nRF24_CE, enable); HAL_GPIO_WritePin(nRF24_GPIO_CE_port, nRF24_GPIO_CE_pin, GPIO_PIN_SET); } /*! * \brief enable CE, set CE low */ static void nRF24_disable_CE() { //gpio_put(nRF24_CE, enable); HAL_GPIO_WritePin(nRF24_GPIO_CE_port, nRF24_GPIO_CE_pin, GPIO_PIN_RESET); } static void nRF24_standby_I() { nRF24_disable_CE(); } /*! * \brief nRF24L01 active FEATURE. nRF24L01+ does not need this function */ uint8_t nRF24_activate() { uint8_t ret; uint8_t status; uint8_t value = 0x73; uint8_t cmd = ACTIVATE; nRF24_spi_enable(); //ret = spi_write_blocking(SPI_PORT, cmd, 2); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Transmit(nRF24_SPI, &value, 1, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief 1. set SPI pin and initialize. * 2.set nRF24L01 to standby-I mode * \param spi SPI handle * \param Csn_port GPIO port * \param Csn_pin GPIO pin * \param ce_port nRF24L01 CE GPIO port * \param ce_pin nRF240L01 CE GPIO pin * \param irq_port nRF24L01 IRQ GPIO port * \param irq_pin nRF24L01 IRQ GPIO pin */ void nRF24_spi_init(SPI_HandleTypeDef* spi, GPIO_TypeDef* csn_port, uint32_t csn_pin, GPIO_TypeDef* ce_port, uint32_t ce_pin, GPIO_TypeDef* irq_port, uint32_t irq_pin) { nRF24_SPI = spi; nRF24_GPIO_CSn_port = csn_port; nRF24_GPIO_CSn_pin = csn_pin; nRF24_GPIO_CE_port = ce_port; nRF24_GPIO_CE_pin = ce_pin; nRF24_GPIO_IRQ_port = irq_port; nRF24_GPIO_IRQ_pin = irq_pin; nRF24_reset_REGISTER(); nRF24_config_PWR_UP(); //nRF24_activate(); //nRF24L01 Product Specification nRF24_disable_CE(); //standby-I HAL_Delay(1); } /*! * \brief enable SPI, set CS LOW. */ void nRF24_spi_enable() { HAL_GPIO_WritePin(nRF24_GPIO_CSn_port, nRF24_GPIO_CSn_pin, GPIO_PIN_RESET); } /*! * \brief disable SPI, set CS HIGH. */ void nRF24_spi_disable() { HAL_GPIO_WritePin(nRF24_GPIO_CSn_port, nRF24_GPIO_CSn_pin, GPIO_PIN_SET); } /*! * \brief read nRF24L01 register * \param REGISTER register address * \param value read out data * \param len read out bytes * \return HAL_status */ uint8_t nRF24_read_REGISTER(uint8_t REGISTER, uint8_t *value, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd=R_REGISTER|REGISTER; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status,1 , nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Receive(nRF24_SPI, value, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief write data into nRF24L01 register * \param REGISTER register address * \param value write data * \param len write bytes * \return HAL status */ uint8_t nRF24_write_REGISTER(uint8_t REGISTER, uint8_t *value, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd =W_REGISTER | REGISTER; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Transmit(nRF24_SPI, value, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(0); return ret; } /*! * \brief R_RX_PL_WIN: nRF24L01 received payload width * \param width payload width */ uint8_t nRF24_get_RX_payload_width(uint8_t *width) { uint8_t ret; uint8_t status; uint8_t cmd=R_RX_PL_WID; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Receive(nRF24_SPI, width, 1, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief R_RX_PAYLOAD: received payload * \param payload received payload * \param len received number of bytes * \return HAL status */ uint8_t nRF24_read_payload(uint8_t *payload, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd=R_RX_PAYLOAD; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Receive(nRF24_SPI, payload, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief W_TX_PAYLOAD: write payload * \param payload received payload * \param len received number of bytes * \return HAL status */ uint8_t nRF24_write_payload(uint8_t *payload, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd = W_TX_PAYLOAD; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Transmit(nRF24_SPI, payload, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief W_TX_PAYLOAD_NOACK: write payload without acknowledgment. enable EN_DYN_ACK in FEATURE * \param payload received payload * \param len received number of bytes * \return HAL staus */ uint8_t nRF24_write_payload_no_ack(uint8_t *payload, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd =W_TX_PAYLOAD_NOACK; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Transmit(nRF24_SPI, payload, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } /*! * \brief FLUSH RX FIFO */ uint8_t nRF24_flush_rx() { uint8_t ret; uint8_t cmd=FLUSH_RX; uint8_t status; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); nRF24_spi_disable(); return ret; } /*! * \brief FLUSH TX FIFO */ uint8_t nRF24_flush_tx() { uint8_t ret; uint8_t cmd=FLUSH_TX; uint8_t status; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); nRF24_spi_disable(); return ret; } uint8_t nRF24_reuse_tx_pl() { uint8_t ret; uint8_t cmd=REUSE_TX_PL; uint8_t status; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); nRF24_spi_disable(); return ret; } /*! * \brief W_ACK_PAYLOAD */ uint8_t nRF24_write_ack_payload(uint8_t data_pipe, uint8_t *payload, uint8_t len) { uint8_t ret; uint8_t status; uint8_t cmd=W_ACK_PAYLOAD | (data_pipe&0x07); nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, &status, 1, nRF24_SPI_TIMEOUT); if (ret == HAL_OK) { ret = HAL_SPI_Transmit(nRF24_SPI, payload, len, nRF24_SPI_TIMEOUT); } nRF24_spi_disable(); return ret; } uint8_t nRF24_set_TX_addr(uint8_t *addr, uint8_t len) { return (nRF24_write_REGISTER(TX_ADDR, addr, len)); } uint8_t nRF24_get_TX_addr(uint8_t *addr, uint8_t len) { return (nRF24_read_REGISTER(TX_ADDR, addr, len)); } uint8_t nRF24_set_RX_addr(uint8_t data_pipe, uint8_t *addr, uint8_t len) { uint8_t rx_addr_reg = RX_ADDR_P0 + data_pipe; if (data_pipe > 1) len = 1; return (nRF24_write_REGISTER(rx_addr_reg, addr, len)); } uint8_t nRF24_get_RX_addr(uint8_t data_pipe, uint8_t *addr, uint8_t len) { uint8_t rx_addr_reg = RX_ADDR_P0 + data_pipe; if (data_pipe > 1) len = 1; return (nRF24_read_REGISTER(rx_addr_reg, addr, len)); } uint8_t nRF24_status(uint8_t *status) { uint8_t ret; uint8_t cmd = NOP; nRF24_spi_enable(); ret = HAL_SPI_TransmitReceive(nRF24_SPI, &cmd, status, 1, nRF24_SPI_TIMEOUT); nRF24_spi_disable(); return ret; } /*! * \param channel 0~125 */ uint8_t nRF24_set_RF_channel(uint8_t channel) { if (channel > 125) channel = 125; return (nRF24_write_REGISTER(RF_CH, &channel,1)); } /*! * \param pa: PA_0dBM, PA_m_6dBm(-6dBm), PA_m_12dBm, PA_m_18dBm */ uint8_t nRF24_set_power_amplifier(uint8_t pa) { uint8_t rf_setup; if(nRF24_read_REGISTER(RF_SETUP, &rf_setup,1) != HAL_OK) return HAL_ERROR; rf_setup &= 0xF9; switch(pa) { case PA_0dBm: rf_setup |= 0x06; break; case PA_m_6dBm: rf_setup |= 0x04; break; case PA_m_12dBm: rf_setup |= 0x02; break; case PA_m_18dBm: rf_setup |= 0x00; break; } return (nRF24_write_REGISTER(RF_SETUP, &rf_setup,1)); } /*! * \param aw 3~5 */ uint8_t nRF24_set_address_width(uint8_t aw) { if (aw >=3 && aw <= 5 ) { aw -= 2; return (nRF24_write_REGISTER(SETUP_AW, &aw,1)); } else return HAL_ERROR; } uint8_t nRF24_get_address_width(uint8_t *aw) { if (nRF24_read_REGISTER(SETUP_AW, aw,1) != HAL_OK) { *aw=0; return HAL_ERROR; } *aw = *aw+2; return HAL_OK; } /*! * \brief EN_AA register */ uint8_t nRF24_enable_auto_ack(uint8_t data_pipe, uint8_t enable) { uint8_t aa; uint8_t mask; if (data_pipe < 0 || data_pipe > 5) return HAL_ERROR; mask = 0x1 << data_pipe; if(nRF24_read_REGISTER(EN_AA, &aa, 1) != HAL_OK) return HAL_ERROR; if (enable) { aa |= mask; } else { aa &= (mask^0xFF); } return (nRF24_write_REGISTER(EN_AA, &aa,1)); } /*! * \param feature FEATURE_EN_DYN_ACK, FEATURE_EN_ACK_PAY, FEATURE_EN_DPL * \param enable true:enable, false:disable */ uint8_t nRF24_enable_feature(uint8_t feature, uint8_t enable) { uint8_t buff; if(nRF24_read_REGISTER(FEATURE, &buff, 1) != HAL_OK) return HAL_ERROR; if (enable) { buff |= (0x01 << feature); } else { buff &= ((0x01 << feature) ^ 0xFF); } return (nRF24_write_REGISTER(FEATURE, &buff,1)); } /*! * \brief DYNPD register */ uint8_t nRF24_enable_data_pipe_dynamic_payload_length(uint8_t data_pipe, uint8_t enable) { if (data_pipe < 0 || data_pipe > 5) return HAL_ERROR; if (nRF24_enable_feature(FEATURE_EN_DPL, 1) != HAL_OK) return HAL_ERROR; if (nRF24_enable_auto_ack(data_pipe, 1) != HAL_OK) return HAL_ERROR; uint8_t dynpd; uint8_t mask; mask = 0x1 << data_pipe; if(nRF24_read_REGISTER(DYNPD, &dynpd, 1) != HAL_OK) return HAL_ERROR; if (enable) { dynpd |= mask; } else { dynpd &= (mask^0xff); } return (nRF24_write_REGISTER(DYNPD, &dynpd,1)); } /*! * \brief Received Power Detector (RPD) */ uint8_t nRF24_get_RPD(uint8_t *rpd_value) { return (nRF24_read_REGISTER(RPD, rpd_value, 1)); } /*! * \brief RX_PW_Px register, Number of bytes in RX payload in data pipe Px */ uint8_t nRF24_set_recv_payload_width(uint8_t data_pipe, uint8_t width) { if (width > 32 || width < 0) return HAL_ERROR; uint8_t rx_pw_px = RX_PW_P0+data_pipe; return (nRF24_write_REGISTER(rx_pw_px, &width, 1)); } /*! * \brief enable RX Address at data pipe x * \param mask 0b00xxxxxx: ex. 0b00010111 enable p0~2 & p4 */ uint8_t nRF24_enable_RXADDR(uint8_t mask) { return (nRF24_write_REGISTER(EN_RXADDR, &mask, 1)); } uint8_t nRF24_set_data_rate(uint8_t rate) { uint8_t rf_setup; if(nRF24_read_REGISTER(RF_SETUP, &rf_setup, 1) != HAL_OK) return HAL_ERROR; rf_setup &= 0xD7; switch(rate) { case DATA_RATE_250K: rf_setup |= 0x20; break; case DATA_RATE_1M: rf_setup |= 0x00; break; case DATA_RATE_2M: rf_setup |= 0x08; break; } return (nRF24_write_REGISTER(RF_SETUP, &rf_setup,1)); } /*! * \brief set nRF24L01+ mode * \param PRIM_RX 1:PRX, 0: PTX * \return HAL status */ uint8_t nRF24_config_mode(uint8_t PRIM_RX) { uint8_t ret; uint8_t mode; ret = nRF24_read_REGISTER(CONFIG, &mode, 1); if (ret == HAL_OK) { nRF24_disable_CE(); HAL_Delay(1); mode = (mode & 0xFE) | (PRIM_RX & 0x01); ret = nRF24_write_REGISTER(CONFIG, &mode,1); nRF24_enable_CE(); HAL_Delay(1); } return ret; } /*! * \param irq_type EVENT_MAX_RT, EVENT_TX_DS, EVENT_RX_DR * \param enable */ uint8_t nRF24_enable_IRQ(uint8_t irq_type, uint8_t enable) { if (irq_type < EVENT_MAX_RT || irq_type > EVENT_RX_DR) return HAL_ERROR; uint8_t config; uint8_t mask=0x01 << irq_type; if (nRF24_read_REGISTER(CONFIG, &config, 1) != HAL_OK) return HAL_ERROR; if (enable) { config &= (mask ^ 0xFF); } else { config |= mask; } return nRF24_write_REGISTER(CONFIG, &config, 1); } /*! * \brief clear MAX_RT interrupt */ uint8_t nRF24_clear_MAX_RT() { uint8_t status; if (nRF24_status(&status) != HAL_OK) return HAL_ERROR; if (status & 0x10) { status |= 0x10; return (nRF24_write_REGISTER(STATUS, &status, 1)); } return HAL_ERROR; } /*! * \brief clear TX_DS interrupt */ uint8_t nRF24_clear_TX_DS() { uint8_t status; if (nRF24_status(&status)!=HAL_OK) return HAL_ERROR; if (status & 0x20) { status |= 0x20; return (nRF24_write_REGISTER(STATUS, &status, 1)); } return HAL_ERROR; } /*! * \brief clear RX_DR interrupt */ uint8_t nRF24_clear_RX_DR() { uint8_t status; if (nRF24_status(&status) != HAL_OK) return HAL_ERROR; if (status & 0x40) { status |= 0x40; return (nRF24_write_REGISTER(STATUS, &status, 1)); } return HAL_ERROR; } static void nRF24_standby_to_txrx_mode(){ nRF24_enable_CE(); //busy_wait_us(140); // Standby modes --> TX/RX mode : max 130us. // Delay from CE positive edge to CSN low : min 4us HAL_Delay(1); } /*! * \brief set SETUP_RETR register bit 7:4 Auto Retransmit Delay * \param delay time = 250us*(delay+1), value:0x00~0x0f */ uint8_t nRF24_set_auto_retransmit_delay(uint8_t delay) { uint8_t ard; if (delay > 0x0f) delay = 0x0f; if (nRF24_read_REGISTER(SETUP_RETR, &ard,1) == HAL_OK) { ard = (ard&0x0f) | delay << 4; return (nRF24_write_REGISTER(SETUP_RETR, &ard, 1)); } return HAL_ERROR; } uint8_t nRF24_fifo_tx_full(uint8_t *full) { uint8_t fifo_status; uint8_t ret; ret = nRF24_read_REGISTER(FIFO_STATUS, &fifo_status, 1); if (ret == HAL_OK) { fifo_status &= 0x20; *full = fifo_status >> 5; } return ret; } uint8_t nRF24_fifo_tx_empty(uint8_t *empty) { uint8_t fifo_status; uint8_t ret; ret = nRF24_read_REGISTER(FIFO_STATUS, &fifo_status, 1); if (ret == HAL_OK) { fifo_status &= 0x10; *empty = fifo_status >> 4; } return ret; } uint8_t nRF24_fifo_rx_full(uint8_t *full) { uint8_t fifo_status; uint8_t ret; ret = nRF24_read_REGISTER(FIFO_STATUS, &fifo_status, 1); if (ret == HAL_OK) { fifo_status &= 0x02; *full = fifo_status >> 1; } return ret; } uint8_t nRF24_fifo_rx_empty(uint8_t *empty) { uint8_t fifo_status; uint8_t ret; ret = nRF24_read_REGISTER(FIFO_STATUS, &fifo_status, 1); if (ret == HAL_OK) { fifo_status &= 0x01; *empty = fifo_status; } return ret; } static void nRF24_reset_REGISTER() { uint8_t value; value=0x3f; nRF24_write_REGISTER(EN_AA, &value, 1); value=0x0a; nRF24_write_REGISTER(CONFIG, &value, 1); value=0x03; nRF24_write_REGISTER(EN_RXADDR, &value, 1); value=0x03; nRF24_write_REGISTER(SETUP_AW, &value, 1); value=0x03; nRF24_write_REGISTER(SETUP_RETR, &value, 1); value=0x02; nRF24_write_REGISTER(RF_CH, &value, 1); value=0x0f; nRF24_write_REGISTER(RF_SETUP, &value, 1); nRF24_flush_rx(); //reset STATUS nRF24_flush_tx(); value=0x0e; nRF24_write_REGISTER(STATUS, &value, 1); value=0x00; nRF24_write_REGISTER(RX_PW_P0, &value, 1); nRF24_write_REGISTER(RX_PW_P1, &value, 1); nRF24_write_REGISTER(RX_PW_P2, &value, 1); nRF24_write_REGISTER(RX_PW_P3, &value, 1); nRF24_write_REGISTER(RX_PW_P4, &value, 1); nRF24_write_REGISTER(RX_PW_P5, &value, 1); nRF24_write_REGISTER(DYNPD, &value, 1); nRF24_write_REGISTER(FEATURE, &value, 1); } /*! * \brief HAL_GPIO_EXTI_Callback used by nRF24L01 driver. User must define nRF24_irq_callback * to get interrupt event * \param event_type EVENT_RX_DR: Receiver Data Ready, * EVENT_TX_DS: Transmitter Data Sent, * EVENT_MAX_RT:Transmitter retransmit * EVENT_GPIO_IRQ: gpio interrupt handler except nRF24L01 IRQ GPIO_pin * \param data_src nRF24L01 datapipe or GPIO_pin * \param data nRF24L01 received data * \param width nRF24L01 received data length */ __weak void nRF24_irq_callback(uint8_t event_type, uint16_t data_src, uint8_t* data, uint8_t width) { switch(event_type) { case EVENT_RX_DR: break; case EVENT_TX_DS: break; case EVENT_MAX_RT: break; case EVENT_GPIO_IRQ: break; } }
- nRF24L01.h
#ifndef __nRF24L01_H__ #define __nRF24L01_H__ // Command #define R_REGISTER 0b00000000 #define W_REGISTER 0b00100000 #define R_RX_PAYLOAD 0b01100001 #define W_TX_PAYLOAD 0b10100000 #define FLUSH_TX 0b11100001 #define FLUSH_RX 0b11100010 #define REUSE_TX_PL 0b11100011 #define ACTIVATE 0b01010000 //nRF24L01 Product Specification #define R_RX_PL_WID 0b01100000 #define W_ACK_PAYLOAD 0b10101000 // 0b10100PPP #define W_TX_PAYLOAD_NOACK 0b10110000 #define NOP 0b11111111 //Registers #define CONFIG 0x00 #define EN_AA 0x01 #define EN_RXADDR 0x02 #define SETUP_AW 0x03 #define SETUP_RETR 0x04 #define RF_CH 0x05 #define RF_SETUP 0x06 #define STATUS 0x07 #define OBSERVE_TX 0x08 #define RPD 0x09 #define RX_ADDR_P0 0x0A #define RX_ADDR_P1 0x0B #define RX_ADDR_P2 0x0C #define RX_ADDR_P3 0x0D #define RX_ADDR_P4 0x0E #define RX_ADDR_P5 0x0F #define TX_ADDR 0x10 #define RX_PW_P0 0x11 #define RX_PW_P1 0x12 #define RX_PW_P2 0x13 #define RX_PW_P3 0x14 #define RX_PW_P4 0x15 #define RX_PW_P5 0x16 #define FIFO_STATUS 0x17 #define DYNPD 0x1C #define FEATURE 0x1D #define TRANSMITTER 0 #define RECEIVER 1 typedef enum { DATA_RATE_250K=0, DATA_RATE_1M, DATA_RATE_2M } nRF24_DATA_RATE; typedef enum { PA_0dBm=0, PA_m_6dBm, PA_m_12dBm, PA_m_18dBm, } nRF24_PA; typedef enum { AW_3=1, AW_4, AW_5, } nRF24_ADDRESS_WIDTH; typedef enum { FEATURE_EN_DYN_ACK=0, // W_TX_PAYLOAD_NOACK FEATURE_EN_ACK_PAY, FEATURE_EN_DPL, }nRF24_FEATURE_MASK; typedef enum { EVENT_MAX_RT=4, EVENT_TX_DS, EVENT_RX_DR, EVENT_GPIO_IRQ, } nRF24_IRQ_EVENT; //typedef void (*nRF24_irq_callback_t)(uint8_t evant_type, uint16_t data_src, uint8_t* data, uint8_t width); void nRF24_spi_init(SPI_HandleTypeDef* spi,GPIO_TypeDef* csn_port, uint32_t csn_pin, GPIO_TypeDef* ce_port, uint32_t ce_pin, GPIO_TypeDef* irq_port, uint32_t irq_pin); uint8_t nRF24_status(uint8_t *status); uint8_t nRF24_read_REGISTER(uint8_t REGISTER, uint8_t *value, uint8_t len); uint8_t nRF24_write_REGISTER(uint8_t REGISTER, uint8_t *value, uint8_t len); uint8_t nRF24_config_mode(uint8_t PRIM_RX); uint8_t nRF24_set_data_rate(uint8_t rate); uint8_t nRF24_set_RF_channel(uint8_t channel); uint8_t nRF24_set_power_amplifier(uint8_t pa); uint8_t nRF24_set_address_width(uint8_t aw); uint8_t nRF24_set_auto_retransmit_delay(uint8_t delay); uint8_t nRF24_set_recv_payload_width(uint8_t data_pipe, uint8_t width); uint8_t nRF24_set_RX_addr(uint8_t data_pipe, uint8_t *addr, uint8_t len); uint8_t nRF24_set_TX_addr(uint8_t *addr, uint8_t len); uint8_t nRF24_get_RPD(uint8_t *rpd_value); uint8_t nRF24_get_RX_payload_width(uint8_t *width); uint8_t nRF24_get_address_width(uint8_t *aw); uint8_t nRF24_get_auto_retransmit_delay(uint8_t *delay); uint8_t nRF24_get_RX_addr(uint8_t data_pipe, uint8_t *addr, uint8_t len); uint8_t nRF24_get_TX_addr(uint8_t *addr, uint8_t len); uint8_t nRF24_enable_auto_ack(uint8_t data_pipe, uint8_t enable); uint8_t nRF24_enable_data_pipe_dynamic_payload_length(uint8_t data_pipe, uint8_t enable); uint8_t nRF24_enable_feature(uint8_t feature, uint8_t enable); uint8_t nRF24_enable_RXADDR(uint8_t mask); uint8_t nRF24_read_payload(uint8_t *payload, uint8_t len); uint8_t nRF24_write_payload(uint8_t *payload, uint8_t len); uint8_t nRF24_write_payload_no_ack(uint8_t *payload, uint8_t len); uint8_t nRF24_flush_rx(); uint8_t nRF24_flush_tx(); uint8_t nRF24_reuse_tx_pl(); uint8_t nRF24_write_ack_payload(uint8_t data_pipe, uint8_t *payload, uint8_t len); uint8_t nRF24_clear_MAX_RT(); uint8_t nRF24_clear_TX_DS(); uint8_t nRF24_clear_RX_DR(); uint8_t nRF24_fifo_tx_full(uint8_t *full); uint8_t nRF24_fifo_rx_full(uint8_t *full); uint8_t nRF24_fifo_tx_empty(uint8_t *empty); uint8_t nRF24_fifo_rx_empty(uint8_t *empty); void nRF24_irq_callback(uint8_t event_type, uint16_t data_src, uint8_t* data, uint8_t width); #endif
沒有留言:
張貼留言