commit
4ede660471
@ -0,0 +1,175 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "iface_nordic.h" |
||||||
|
#include "nrf_pins.h" |
||||||
|
#include "resources.h" |
||||||
|
#include "hw_utils.h" |
||||||
|
#include "nrf.h" |
||||||
|
#include "unit_base.h" |
||||||
|
#include "system_settings.h" |
||||||
|
#include "utils/hexdump.h" |
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle; |
||||||
|
|
||||||
|
#define RX_PIPE_NUM 0 |
||||||
|
|
||||||
|
void iface_nordic_claim_resources(void) |
||||||
|
{ |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_SPI)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_CE)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_NSS)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_IRQ)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_MISO)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_MOSI)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_SCK)); |
||||||
|
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_EXTI0+NRF_EXTI_LINENUM)); |
||||||
|
} |
||||||
|
|
||||||
|
void iface_nordic_free_resources(void) |
||||||
|
{ |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_SPI); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_CE); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_NSS); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_IRQ); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_MISO); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_MOSI); |
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_SCK); |
||||||
|
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_EXTI0+NRF_EXTI_LINENUM); |
||||||
|
} |
||||||
|
|
||||||
|
static uint8_t rx_buffer[32]; |
||||||
|
|
||||||
|
static void NrfIrqHandler(void *arg) |
||||||
|
{ |
||||||
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
dbg_nrf("[EXTI] ---"); |
||||||
|
|
||||||
|
while (NRF_IsRxPacket()) { |
||||||
|
uint8_t pipenum; |
||||||
|
uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum); |
||||||
|
if (count > 0) { |
||||||
|
dbg_nrf("NRF RX %d bytes", (int) count); |
||||||
|
rxQuePostMsg(rx_buffer, count); |
||||||
|
} |
||||||
|
else { |
||||||
|
dbg("IRQ but no Rx"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dbg_nrf("--- end [EXTI]"); |
||||||
|
} |
||||||
|
|
||||||
|
bool iface_nordic_init(void) |
||||||
|
{ |
||||||
|
dbg("Setting up Nordic..."); |
||||||
|
|
||||||
|
hw_periph_clock_enable(NRF_SPI); |
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_SCK, NRF_SPI_AF)); |
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MOSI, NRF_SPI_AF)); |
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MISO, NRF_SPI_AF)); |
||||||
|
|
||||||
|
// Manual pins
|
||||||
|
LL_GPIO_SetPinMode(NRF_NSS_GPIO_Port, NRF_NSS_Pin, LL_GPIO_MODE_OUTPUT); |
||||||
|
LL_GPIO_SetPinMode(NRF_CE_GPIO_Port, NRF_CE_Pin, LL_GPIO_MODE_OUTPUT); |
||||||
|
LL_GPIO_SetPinMode(NRF_IRQ_GPIO_Port, NRF_IRQ_Pin, LL_GPIO_MODE_INPUT); |
||||||
|
|
||||||
|
LL_SPI_Disable(NRF_SPI); |
||||||
|
{ |
||||||
|
LL_SPI_SetBaudRatePrescaler(NRF_SPI, LL_SPI_BAUDRATEPRESCALER_DIV32); |
||||||
|
//LL_SPI_BAUDRATEPRESCALER_DIV8
|
||||||
|
|
||||||
|
LL_SPI_SetClockPolarity(NRF_SPI, LL_SPI_POLARITY_LOW); |
||||||
|
LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_1EDGE); |
||||||
|
LL_SPI_SetTransferDirection(NRF_SPI, LL_SPI_FULL_DUPLEX); |
||||||
|
LL_SPI_SetTransferBitOrder(NRF_SPI, LL_SPI_MSB_FIRST); |
||||||
|
|
||||||
|
LL_SPI_SetNSSMode(NRF_SPI, LL_SPI_NSS_SOFT); |
||||||
|
LL_SPI_SetDataWidth(NRF_SPI, LL_SPI_DATAWIDTH_8BIT); |
||||||
|
LL_SPI_SetRxFIFOThreshold(NRF_SPI, LL_SPI_RX_FIFO_TH_QUARTER); // trigger RXNE on 1 byte
|
||||||
|
|
||||||
|
LL_SPI_SetMode(NRF_SPI, LL_SPI_MODE_MASTER); |
||||||
|
} |
||||||
|
LL_SPI_Enable(NRF_SPI); |
||||||
|
|
||||||
|
|
||||||
|
dbg("configure nrf module"); |
||||||
|
|
||||||
|
// Now configure the radio
|
||||||
|
NRF_Init(NRF_SPEED_2M); // TODO configurable speed
|
||||||
|
NRF_SetChannel(SystemSettings.nrf_channel); |
||||||
|
NRF_SetBaseAddress(SystemSettings.nrf_network); |
||||||
|
NRF_SetRxAddress(RX_PIPE_NUM, SystemSettings.nrf_address); |
||||||
|
NRF_EnablePipe(RX_PIPE_NUM); |
||||||
|
NRF_ModeRX(); |
||||||
|
|
||||||
|
dbg("enable exti"); |
||||||
|
// EXTI
|
||||||
|
LL_EXTI_EnableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
LL_EXTI_EnableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
LL_SYSCFG_SetEXTISource(NRF_SYSCFG_EXTI_PORT, LL_SYSCFG_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
irqd_attach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler, NULL); |
||||||
|
// TODO increase priority in NVIC?
|
||||||
|
|
||||||
|
dbg("nrf setup done"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void iface_nordic_deinit(void) |
||||||
|
{ |
||||||
|
LL_EXTI_DisableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]); |
||||||
|
irqd_detach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler); |
||||||
|
hw_periph_clock_disable(NRF_SPI); |
||||||
|
|
||||||
|
hw_deinit_pin_rsc(NRF_R_SCK); |
||||||
|
hw_deinit_pin_rsc(NRF_R_MOSI); |
||||||
|
hw_deinit_pin_rsc(NRF_R_MISO); |
||||||
|
hw_deinit_pin_rsc(NRF_R_NSS); |
||||||
|
hw_deinit_pin_rsc(NRF_R_CE); |
||||||
|
hw_deinit_pin_rsc(NRF_R_IRQ); |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME
|
||||||
|
#define MAX_RETRY 5 |
||||||
|
|
||||||
|
void iface_nordic_transmit(const uint8_t *buff, uint32_t len) |
||||||
|
{ |
||||||
|
bool suc = false; |
||||||
|
while (len > 0) { |
||||||
|
uint8_t chunk = (uint8_t) MIN(32, len); |
||||||
|
|
||||||
|
uint16_t delay = 1; |
||||||
|
//hexDump("Tx chunk", buff, chunk);
|
||||||
|
for (int i = 0; i < MAX_RETRY; i++) { |
||||||
|
suc = NRF_SendPacket(RX_PIPE_NUM, buff, chunk); // use the pipe to retrieve the address
|
||||||
|
if (!suc) { |
||||||
|
vTaskDelay(delay); |
||||||
|
delay *= 2; // longer delay next time
|
||||||
|
} else { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!suc) { |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
buff += chunk; |
||||||
|
len -= chunk; |
||||||
|
} |
||||||
|
|
||||||
|
if (suc) { |
||||||
|
dbg_nrf("+ NRF Tx OK!"); |
||||||
|
} else { |
||||||
|
dbg("- NRF sending failed"); |
||||||
|
} |
||||||
|
|
||||||
|
// give when it's done
|
||||||
|
xSemaphoreGive(semVcomTxReadyHandle); // similar to how it's done in USB - this is called in the Tx Done handler
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_IFACE_NORDIC_H |
||||||
|
#define GEX_F072_IFACE_NORDIC_H |
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
void iface_nordic_claim_resources(void); |
||||||
|
|
||||||
|
void iface_nordic_free_resources(void); |
||||||
|
|
||||||
|
void iface_nordic_deinit(void); |
||||||
|
|
||||||
|
bool iface_nordic_init(void); |
||||||
|
|
||||||
|
void iface_nordic_transmit(const uint8_t *buff, uint32_t len); |
||||||
|
|
||||||
|
#endif //GEX_F072_IFACE_NORDIC_H
|
@ -0,0 +1,105 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
#include "iface_uart.h" |
||||||
|
#include "resources.h" |
||||||
|
#include "hw_utils.h" |
||||||
|
#include "irq_dispatcher.h" |
||||||
|
#include "task_msg.h" |
||||||
|
#include "system_settings.h" |
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle; |
||||||
|
|
||||||
|
static uint32_t usart_rxi = 0; |
||||||
|
static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE]; |
||||||
|
static uint32_t last_rx_time = 0; |
||||||
|
|
||||||
|
void iface_uart_claim_resources(void) |
||||||
|
{ |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_USART2)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA2)); |
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA3)); |
||||||
|
} |
||||||
|
|
||||||
|
void iface_uart_free_resources(void) |
||||||
|
{ |
||||||
|
rsc_free(&UNIT_SYSTEM, R_USART2); |
||||||
|
rsc_free(&UNIT_SYSTEM, R_PA2); |
||||||
|
rsc_free(&UNIT_SYSTEM, R_PA3); |
||||||
|
} |
||||||
|
|
||||||
|
/** Handler for the USART transport */ |
||||||
|
static void com_UsartIrqHandler(void *arg) |
||||||
|
{ |
||||||
|
(void)arg; |
||||||
|
if (LL_USART_IsActiveFlag_RXNE(USART2)) { |
||||||
|
vPortEnterCritical(); |
||||||
|
{ |
||||||
|
usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2); |
||||||
|
if (usart_rxi == MSG_QUE_SLOT_SIZE) { |
||||||
|
rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq
|
||||||
|
usart_rxi = 0; |
||||||
|
} |
||||||
|
last_rx_time = HAL_GetTick(); |
||||||
|
} |
||||||
|
vPortExitCritical(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** this is called from the hal tick irq */ |
||||||
|
void com_iface_flush_buffer(void) |
||||||
|
{ |
||||||
|
if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) { |
||||||
|
vPortEnterCritical(); |
||||||
|
{ |
||||||
|
rxQuePostMsg(usart_rx_buffer, usart_rxi); |
||||||
|
usart_rxi = 0; |
||||||
|
} |
||||||
|
vPortExitCritical(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool iface_uart_init(void) |
||||||
|
{ |
||||||
|
dbg("Setting up UART transfer"); |
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1)); |
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1)); |
||||||
|
|
||||||
|
__HAL_RCC_USART2_CLK_ENABLE(); |
||||||
|
__HAL_RCC_USART2_FORCE_RESET(); |
||||||
|
__HAL_RCC_USART2_RELEASE_RESET(); |
||||||
|
|
||||||
|
LL_USART_Disable(USART2); |
||||||
|
|
||||||
|
LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud); |
||||||
|
dbg("baud = %d", (int)SystemSettings.comm_uart_baud); |
||||||
|
|
||||||
|
irqd_attach(USART2, com_UsartIrqHandler, NULL); |
||||||
|
LL_USART_EnableIT_RXNE(USART2); |
||||||
|
LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX); |
||||||
|
|
||||||
|
LL_USART_Enable(USART2); |
||||||
|
|
||||||
|
return true; // always OK (TODO check voltage on Rx if it's 3V3 when idle?)
|
||||||
|
} |
||||||
|
|
||||||
|
void iface_uart_deinit(void) |
||||||
|
{ |
||||||
|
// this doesn't normally happen
|
||||||
|
hw_deinit_pin_rsc(R_PA2); |
||||||
|
hw_deinit_pin_rsc(R_PA3); |
||||||
|
__HAL_RCC_USART2_CLK_DISABLE(); |
||||||
|
irqd_detach(USART2, com_UsartIrqHandler); |
||||||
|
} |
||||||
|
|
||||||
|
void iface_uart_transmit(const uint8_t *buff, uint32_t len) |
||||||
|
{ |
||||||
|
// TODO rewrite this to use DMA, then wait for the DMA
|
||||||
|
for(uint32_t i=0;i<len;i++) { |
||||||
|
while(!LL_USART_IsActiveFlag_TXE(USART2)); |
||||||
|
LL_USART_TransmitData8(USART2, buff[i]); |
||||||
|
} |
||||||
|
xSemaphoreGive(semVcomTxReadyHandle); // act as if we just finished it and this is perhaps the DMA irq
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_IFACE_UART_H |
||||||
|
#define GEX_F072_IFACE_UART_H |
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
void com_iface_flush_buffer(void); |
||||||
|
|
||||||
|
void iface_uart_deinit(void); |
||||||
|
bool iface_uart_init(void); |
||||||
|
|
||||||
|
void iface_uart_free_resources(void); |
||||||
|
void iface_uart_claim_resources(void); |
||||||
|
|
||||||
|
void iface_uart_transmit(const uint8_t *buff, uint32_t len); |
||||||
|
|
||||||
|
#endif //GEX_F072_IFACE_UART_H
|
@ -0,0 +1,73 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "iface_usb.h" |
||||||
|
#include "TinyFrame.h" |
||||||
|
#include "system_settings.h" |
||||||
|
#include "USB/usb_device.h" |
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle; |
||||||
|
extern osMutexId mutTinyFrameTxHandle; |
||||||
|
|
||||||
|
bool iface_usb_ready(void) |
||||||
|
{ |
||||||
|
return 0 != (USB->DADDR & USB_DADDR_ADD); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* USB transmit implementation |
||||||
|
* |
||||||
|
* @param buff - buffer to send (can be longer than the buffers) |
||||||
|
* @param len - buffer size |
||||||
|
*/ |
||||||
|
void iface_usb_transmit(const uint8_t *buff, uint32_t len) |
||||||
|
{ |
||||||
|
#if 1 |
||||||
|
const uint32_t real_size = len; |
||||||
|
|
||||||
|
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
|
||||||
|
if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason
|
||||||
|
uint32_t pad = (64 - (len&0x3F)); |
||||||
|
memset((void *) (buff + len), 0, pad); |
||||||
|
len += pad; // padding to a multiple of 64 (size of the endpoint)
|
||||||
|
} |
||||||
|
|
||||||
|
// We bypass the USBD driver library's overhead by using the HAL function directly
|
||||||
|
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len)); |
||||||
|
|
||||||
|
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
|
||||||
|
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
|
||||||
|
|
||||||
|
// If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion
|
||||||
|
if (real_size == TF_SENDBUF_LEN) { |
||||||
|
// TODO this seems wrong - investigate
|
||||||
|
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) { |
||||||
|
TF_Error("Tx stalled in WriteImpl"); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
#else |
||||||
|
(void) tf; |
||||||
|
#define CHUNK 64 // size of the USB packet
|
||||||
|
int32_t total = (int32_t) len; |
||||||
|
while (total > 0) { |
||||||
|
const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100); |
||||||
|
if (mxStatus != osOK) { |
||||||
|
TF_Error("Tx stalled"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK); |
||||||
|
|
||||||
|
// this is an attempt to speed it up a little by removing a couple levels of indirection
|
||||||
|
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize)); |
||||||
|
|
||||||
|
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
|
||||||
|
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
||||||
|
|
||||||
|
buff += chunksize; |
||||||
|
total -= chunksize; |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_IFACE_USB_H |
||||||
|
#define GEX_F072_IFACE_USB_H |
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
bool iface_usb_ready(void); |
||||||
|
|
||||||
|
/**
|
||||||
|
* USB transmit implementation |
||||||
|
* |
||||||
|
* @param buff - buffer to send (can be longer than the buffers) |
||||||
|
* @param len - buffer size |
||||||
|
*/ |
||||||
|
void iface_usb_transmit(const uint8_t *buff, uint32_t len); |
||||||
|
|
||||||
|
#endif //GEX_F072_IFACE_USB_H
|
@ -0,0 +1,530 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/02.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
#include "nrf.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) |
||||||
|
|
||||||
|
// 12 for 72 MHz
|
||||||
|
#define _delay_us(n) __asm_loop((n)*8) |
||||||
|
|
||||||
|
static inline void CE(bool level) { |
||||||
|
__asm_loop(1); |
||||||
|
if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); |
||||||
|
else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin); |
||||||
|
__asm_loop(1); |
||||||
|
} |
||||||
|
|
||||||
|
static inline void NSS(bool level) { |
||||||
|
__asm_loop(1); |
||||||
|
if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); |
||||||
|
else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin); |
||||||
|
__asm_loop(1); |
||||||
|
} |
||||||
|
|
||||||
|
static uint8_t spi(uint8_t tx) { |
||||||
|
while (! LL_SPI_IsActiveFlag_TXE(NRF_SPI)); |
||||||
|
LL_SPI_TransmitData8(NRF_SPI, tx); |
||||||
|
while (! LL_SPI_IsActiveFlag_RXNE(NRF_SPI)); |
||||||
|
return LL_SPI_ReceiveData8(NRF_SPI); |
||||||
|
} |
||||||
|
|
||||||
|
//-------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 |
||||||
|
|
||||||
|
#define RD_FIFO_STATUS_RX_EMPTY 0x01 |
||||||
|
#define RD_FIFO_STATUS_RX_FULL 0x02 |
||||||
|
#define RD_FIFO_STATUS_TX_EMPTY 0x10 |
||||||
|
#define RD_FIFO_STATUS_TX_FULL 0x20 |
||||||
|
#define RD_FIFO_STATUS_TX_REUSE 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) |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
dbg_nrf("Wr[0x%02x] := 0x%02x", (int)reg, (int) value); |
||||||
|
|
||||||
|
|
||||||
|
uint8_t reg_val = 0; |
||||||
|
CHIPSELECT { |
||||||
|
spi(CMD_READ_REG | reg); |
||||||
|
reg_val = spi(0); |
||||||
|
} |
||||||
|
dbg_nrf(" verify 0x%02x", (int)reg_val); |
||||||
|
if (reg_val != value) |
||||||
|
dbg_nrf(" !!!"); |
||||||
|
else |
||||||
|
dbg_nrf(" OK"); |
||||||
|
|
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
dbg_nrf("Rd[0x%02x] = 0x%02x", (int)reg, (int) reg_val); |
||||||
|
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; |
||||||
|
|
||||||
|
// write it to the two full-width address registers
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); |
||||||
|
nrf_base_address[4] = 1;// to be different
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5); |
||||||
|
} |
||||||
|
|
||||||
|
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte) |
||||||
|
{ |
||||||
|
if (pipenum > 5) { |
||||||
|
dbg_nrf("!! bad pipe %d", pipenum); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
nrf_base_address[4] = AddrByte; |
||||||
|
|
||||||
|
nrf_pipe_addr[pipenum] = AddrByte; |
||||||
|
|
||||||
|
dbg_nrf("Set Rx addr (pipe %d) = 0x%02x", (int)pipenum, AddrByte); |
||||||
|
if (pipenum == 0) { |
||||||
|
dbg_nrf("W ADDR_PA0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); |
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); |
||||||
|
} |
||||||
|
else if (pipenum == 1) { |
||||||
|
dbg_nrf("W ADDR_PA1: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); |
||||||
|
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) |
||||||
|
{ |
||||||
|
dbg_nrf("Enable pipe num %d", (int)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; |
||||||
|
|
||||||
|
dbg_nrf("W Tx_ADDR + Rx0: %02X-%02X-%02X-%02X-%02X", |
||||||
|
nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]); |
||||||
|
|
||||||
|
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) |
||||||
|
{ |
||||||
|
dbg_nrf("PDn"); |
||||||
|
CE(0); |
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits); |
||||||
|
} |
||||||
|
|
||||||
|
void NRF_ModeTX(void) |
||||||
|
{ |
||||||
|
dbg_nrf("Tx Mode"); |
||||||
|
|
||||||
|
CE(0); |
||||||
|
uint8_t m = NRF_ReadRegister(RG_CONFIG); |
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP); |
||||||
|
if ((m & RD_CONFIG_PWR_UP) == 0) { |
||||||
|
// switching on
|
||||||
|
LL_mDelay(5); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void NRF_ModeRX(void) |
||||||
|
{ |
||||||
|
dbg_nrf("Rx Mode"); |
||||||
|
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
|
||||||
|
CE(1); |
||||||
|
|
||||||
|
//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()) {
|
||||||
|
// dbg("rx queue empty");
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
// CE(0); // quit Rx mode - go idle
|
||||||
|
|
||||||
|
CHIPSELECT { |
||||||
|
status = spi(CMD_RD_RX_PL_WIDTH); |
||||||
|
pw = spi(0); |
||||||
|
} |
||||||
|
|
||||||
|
if (pw == 0) { |
||||||
|
dbg("empty pld"); |
||||||
|
} |
||||||
|
|
||||||
|
if (pw > 32) { |
||||||
|
CHIPSELECT { |
||||||
|
spi(CMD_FLUSH_RX); |
||||||
|
} |
||||||
|
pw = 0; |
||||||
|
dbg("over 32"); |
||||||
|
} else { |
||||||
|
// 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
|
||||||
|
|
||||||
|
// if ((orig_conf & RD_CONFIG_PWR_UP) == 0) {
|
||||||
|
// dbg_nrf("going back PwrDn");
|
||||||
|
// NRF_PowerDown();
|
||||||
|
// }
|
||||||
|
// else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) {
|
||||||
|
// dbg_nrf("going back PwrUp+Rx");
|
||||||
|
// NRF_ModeRX();
|
||||||
|
// }
|
||||||
|
// CE(1); // back to rx
|
||||||
|
return pw; |
||||||
|
} |
||||||
|
|
||||||
|
bool NRF_IsRxPacket(void) |
||||||
|
{ |
||||||
|
return 0 == (NRF_ReadRegister(RG_FIFO_STATUS) & RD_FIFO_STATUS_RX_EMPTY); |
||||||
|
// 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_nrf("!! Pipe %d not enabled", PipeNum); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
dbg_nrf("Will tx to addr %02x", nrf_pipe_addr[PipeNum]); |
||||||
|
|
||||||
|
const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG); |
||||||
|
CE(0); |
||||||
|
NRF_ModeTX(); // Make sure in TX mode
|
||||||
|
NRF_SetTxAddress(nrf_pipe_addr[PipeNum]); // this sets the Tx addr and also pipe 0 addr for ACK
|
||||||
|
|
||||||
|
CHIPSELECT { |
||||||
|
spi(CMD_FLUSH_TX); |
||||||
|
}; |
||||||
|
|
||||||
|
CHIPSELECT { |
||||||
|
spi(CMD_WR_TX_PLD); |
||||||
|
for (uint8_t i = 0; i < Length; i++) spi(Packet[i]); |
||||||
|
}; |
||||||
|
|
||||||
|
// CE pulse
|
||||||
|
CE(1); |
||||||
|
_delay_us(20); // At least 10 us
|
||||||
|
CE(0); |
||||||
|
|
||||||
|
uint8_t st = 0; |
||||||
|
while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) { |
||||||
|
st = NRF_ReadStatus(); // Packet acked or timed out
|
||||||
|
} |
||||||
|
|
||||||
|
dbg_nrf("Send status: 0x%02x - MAX_RT %d, SENT %d", (int)st, |
||||||
|
(st&RD_STATUS_MAX_RT) != 0, (st&RD_STATUS_TX_DS) != 0); |
||||||
|
|
||||||
|
NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit
|
||||||
|
|
||||||
|
if ((orig_conf & RD_CONFIG_PWR_UP) == 0) { |
||||||
|
dbg_nrf("going back PwrDn"); |
||||||
|
NRF_PowerDown(); |
||||||
|
} |
||||||
|
else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) { |
||||||
|
dbg_nrf("going back PwrUp+Rx"); |
||||||
|
NRF_ModeRX(); |
||||||
|
} |
||||||
|
|
||||||
|
return 0 != (st & RD_STATUS_TX_DS); // success
|
||||||
|
} |
||||||
|
|
||||||
|
void NRF_Init(uint8_t pSpeed) |
||||||
|
{ |
||||||
|
// Set the required output pins
|
||||||
|
NSS(1); |
||||||
|
CE(0); |
||||||
|
|
||||||
|
LL_mDelay(200); |
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) { |
||||||
|
nrf_pipe_addr[i] = 0; |
||||||
|
nrf_pipe_enabled[i] = 0; |
||||||
|
} |
||||||
|
|
||||||
|
// clear flags etc
|
||||||
|
NRF_PowerDown(); |
||||||
|
CHIPSELECT { spi(CMD_FLUSH_RX); } |
||||||
|
CHIPSELECT { spi(CMD_FLUSH_TX); } |
||||||
|
NRF_WriteRegister(RG_STATUS, 0x70); |
||||||
|
|
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits); |
||||||
|
NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_EN_RXADDR, 0x01); // disable all, enable pipe 0 - this is required for shockburst, despite not being specified in the DS
|
||||||
|
|
||||||
|
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
|
||||||
|
// }
|
||||||
|
} |
@ -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 "platform.h" |
||||||
|
#include "resources.h" |
||||||
|
#include "nrf_pins.h" |
||||||
|
|
||||||
|
#define dbg_nrf(...) do{}while(0) |
||||||
|
//#define dbg_nrf(...) dbg(##__VA_ARGS__)
|
||||||
|
|
||||||
|
// 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); |
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
@ -0,0 +1,33 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_NRF_PINS_H |
||||||
|
#define GEX_F072_NRF_PINS_H |
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
// TODO move those to plat_compat?
|
||||||
|
#define NRF_SPI SPI1 |
||||||
|
#define NRF_R_SPI R_SPI1 |
||||||
|
|
||||||
|
#define NRF_IRQ_Pin LL_GPIO_PIN_10 |
||||||
|
#define NRF_IRQ_GPIO_Port GPIOB |
||||||
|
#define NRF_R_IRQ R_PB10 |
||||||
|
#define NRF_EXTI_LINENUM 10 |
||||||
|
#define NRF_SYSCFG_EXTI_PORT LL_SYSCFG_EXTI_PORTB |
||||||
|
|
||||||
|
#define NRF_NSS_Pin LL_GPIO_PIN_11 |
||||||
|
#define NRF_NSS_GPIO_Port GPIOB |
||||||
|
#define NRF_R_NSS R_PB11 |
||||||
|
|
||||||
|
#define NRF_CE_Pin LL_GPIO_PIN_12 |
||||||
|
#define NRF_CE_GPIO_Port GPIOB |
||||||
|
#define NRF_R_CE R_PB12 |
||||||
|
|
||||||
|
#define NRF_R_SCK R_PA5 |
||||||
|
#define NRF_R_MISO R_PA6 |
||||||
|
#define NRF_R_MOSI R_PA7 |
||||||
|
#define NRF_SPI_AF LL_GPIO_AF_0 |
||||||
|
|
||||||
|
#endif //GEX_F072_NRF_PINS_H
|
Loading…
Reference in new issue