nordic implemented, need testing and fixes

remotes/github/master
Ondřej Hruška 6 years ago
parent 9182c666ea
commit 5eec46c041
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 75
      TinyFrame/TF_Integration.c
  2. 165
      comm/iface_nordic.c
  3. 20
      comm/iface_nordic.h
  4. 105
      comm/iface_uart.c
  5. 20
      comm/iface_uart.h
  6. 73
      comm/iface_usb.c
  7. 20
      comm/iface_usb.h
  8. 126
      comm/interfaces.c
  9. 467
      comm/nrf.c
  10. 159
      comm/nrf.h
  11. 33
      comm/nrf_pins.h
  12. 81
      framework/system_settings.c
  13. 11
      gex_hooks.c
  14. 3
      platform/platform.c
  15. 14
      units/digital_in/_din_init.c

@ -8,6 +8,9 @@
#include "task_main.h"
#include "comm/messages.h"
#include "comm/interfaces.h"
#include "comm/iface_uart.h"
#include "comm/iface_nordic.h"
#include "comm/iface_usb.h"
#include "framework/system_settings.h"
#include "USB/usbd_cdc_if.h"
@ -17,76 +20,16 @@
extern osSemaphoreId semVcomTxReadyHandle;
extern osMutexId mutTinyFrameTxHandle;
/**
* USB transmit implementation
*
* @param tf - TF
* @param buff - buffer to send (can be longer than the buffers)
* @param len - buffer size
*/
static inline void _USB_WriteImpl(TinyFrame *tf, 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
}
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
{
if (gActiveComport == COMPORT_USB) {
_USB_WriteImpl(tf, buff, len);
iface_usb_transmit(buff, len);
}
else if (gActiveComport == COMPORT_USART) {
// 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
iface_uart_transmit(buff, len);
}
else if (gActiveComport == COMPORT_NORDIC) {
iface_nordic_transmit(buff, len);
}
else {
// TODO other transports
@ -104,7 +47,7 @@ bool TF_ClaimTx(TinyFrame *tf)
// The last chunk from some previous frame may still be being transmitted,
// wait for it to finish (the semaphore is given in the CDC tx done handler)
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 200)) {
TF_Error("Tx stalled in Claim");
// release the guarding mutex again

@ -0,0 +1,165 @@
//
// 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"
extern osSemaphoreId semVcomTxReadyHandle;
#define RX_PIPE_NUM 1
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]);
uint8_t pipenum;
uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum);
if (count > 0) {
dbg("NRF RX %d bytes", (int)count);
rxQuePostMsg(rx_buffer, count);
} else {
dbg("IRQ but no Rx");
}
}
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_DIV8);
LL_SPI_SetClockPolarity(NRF_SPI, LL_SPI_POLARITY_LOW);
LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_2EDGE);
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_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);
}
#define MAX_RETRY 8
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;
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 += 5; // longer delay next time
} else {
break;
}
}
if (!suc) {
break;
}
buff += chunk;
len -= chunk;
}
if (suc) {
dbg("+ 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

@ -2,7 +2,6 @@
// Created by MightyPork on 2018/03/23.
//
#include <stm32f072xb.h>
#include "platform.h"
#include "usbd_core.h"
#include "USB/usb_device.h"
@ -12,6 +11,10 @@
#include "framework/resources.h"
#include "platform/hw_utils.h"
#include "framework/unit_base.h"
#include "nrf_pins.h"
#include "iface_uart.h"
#include "iface_usb.h"
#include "iface_nordic.h"
enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially
@ -35,36 +38,31 @@ void com_switch_transfer_if_needed(void)
// Check if USB is enumerated
const uint32_t uadr = (USB->DADDR & USB_DADDR_ADD);
if (0 == uadr) {
if (!iface_usb_ready()) {
dbg("Not enumerated, assuming USB is dead");
// Fallback to radio or bare USART
do {
if (SystemSettings.use_comm_nordic) {
if (configure_interface(COMPORT_NORDIC)) {
break;
}
if (configure_interface(COMPORT_NORDIC)) break;
}
#if 0
if (SystemSettings.use_comm_lora) {
if (configure_interface(COMPORT_LORA)) {
break;
}
if (configure_interface(COMPORT_LORA)) break;
}
#endif
if (SystemSettings.use_comm_uart) {
// after nordic/lora
if (configure_interface(COMPORT_USART)) {
break;
}
if (configure_interface(COMPORT_USART)) break;
}
dbg("No alternate com interface configured.");
gActiveComport = COMPORT_NONE;
} while (0);
} else {
dbg("USB got address 0x%02x - OK", (int)uadr);
dbg("USB got address - OK");
}
xfer_verify_done = true;
@ -76,24 +74,11 @@ void com_switch_transfer_if_needed(void)
void com_claim_resources_for_alt_transfers(void)
{
if (SystemSettings.use_comm_uart) {
do {
if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_USART2)) {
SystemSettings.use_comm_uart = false;
break;
}
iface_uart_claim_resources();
}
if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA2)) {
SystemSettings.use_comm_uart = false;
rsc_free(&UNIT_SYSTEM, R_USART2);
break;
}
if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA3)) {
SystemSettings.use_comm_uart = false;
rsc_free(&UNIT_SYSTEM, R_USART2);
rsc_free(&UNIT_SYSTEM, R_PA2);
break;
}
} while (0);
if (SystemSettings.use_comm_nordic) {
iface_nordic_claim_resources();
}
}
@ -101,46 +86,14 @@ void com_claim_resources_for_alt_transfers(void)
void com_release_resources_for_alt_transfers(void)
{
if (SystemSettings.use_comm_uart) {
rsc_free(&UNIT_SYSTEM, R_USART2);
rsc_free(&UNIT_SYSTEM, R_PA2);
rsc_free(&UNIT_SYSTEM, R_PA3);
iface_uart_free_resources();
}
}
static uint32_t usart_rxi = 0;
static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE];
static uint32_t last_rx_time = 0;
/** 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();
if (SystemSettings.use_comm_nordic) {
iface_nordic_free_resources();
}
}
/** 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();
}
}
static bool configure_interface(enum ComportSelection iface)
{
@ -151,14 +104,10 @@ static bool configure_interface(enum ComportSelection iface)
__HAL_RCC_USB_CLK_DISABLE();
}
else if (gActiveComport == COMPORT_USART) {
// 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);
iface_uart_deinit();
}
else if (gActiveComport == COMPORT_NORDIC) {
// TODO
iface_nordic_deinit();
}
@ -170,45 +119,20 @@ static bool configure_interface(enum ComportSelection iface)
return false;
}
else if (iface == COMPORT_USART) {
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?)
return iface_uart_init();
}
else if (iface == COMPORT_NORDIC) {
// Try to configure nordic
dbg("Setting up nRF transfer");
// TODO set up and check nRF transport
// On failure, try setting up LoRa
dbg("nRF failed to init");
return false;
return iface_nordic_init();
}
#if 0
else if (iface == COMPORT_LORA) {
// Try to configure nordic
dbg("Setting up LoRa transfer");
// TODO set up and check LoRa transport
dbg("LoRa failed to init");
dbg("LoRa not impl!");
return false;
}
#endif
else {
trap("Bad iface %d", iface);
}

@ -0,0 +1,467 @@
//
// 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) {
if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
}
static inline void NSS(bool level) {
if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
}
static uint8_t spi(uint8_t tx) {
while (! LL_SPI_IsActiveFlag_TXE(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
// Config register bits (excluding the bottom two that are changed dynamically)
// enable only Rx IRQ
#define ModeBits (RD_CONFIG_DISABLE_IRQ_MAX_RT | \
RD_CONFIG_DISABLE_IRQ_TX_DS | \
RD_CONFIG_EN_CRC | \
RD_CONFIG_CRCO)
#define CEHIGH CE(1)
#define CELOW CE(0)
static inline uint8_t CS(uint8_t hl)
{
if (hl == 1) {
NSS(0);
}
else {
NSS(1);
}
return hl;
}
#define CHIPSELECT for (uint8_t cs = CS(1); cs==1; cs = CS(0))
// Base NRF address - byte 4 may be modified before writing to a pipe register,
// the first 4 bytes are shared in the network. Master is always code 0.
static uint8_t nrf_base_address[5];
static uint8_t nrf_pipe_addr[6];
static bool nrf_pipe_enabled[6];
static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value)
{
uint8_t status = 0;
CHIPSELECT {
status = spi(CMD_WRITE_REG | reg);
spi(value);
}
return status;
}
static uint8_t NRF_ReadRegister(uint8_t reg)
{
uint8_t reg_val = 0;
CHIPSELECT {
spi(CMD_READ_REG | reg);
reg_val = spi(0);
}
return reg_val;
}
static uint8_t NRF_ReadStatus(void)
{
uint8_t reg_val = 0;
CHIPSELECT {
reg_val = spi(CMD_NOP);
}
return reg_val;
}
static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes)
{
uint8_t status = 0, i = 0;
CHIPSELECT {
status = spi(CMD_WRITE_REG | reg);
for (i = 0; i < bytes; i++) {
spi(*pBuf++);
}
}
return status;
}
static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes)
{
uint8_t status = 0, i;
CHIPSELECT {
status = spi(CMD_READ_REG | reg);
for (i = 0; i < bytes; i++) {
pBuf[i] = spi(0);
}
}
return status;
}
void NRF_SetBaseAddress(const uint8_t *Bytes4)
{
memcpy(nrf_base_address, Bytes4, 4);
nrf_base_address[4] = 0;
}
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte)
{
if (pipenum > 5) {
dbg("!! bad pipe %d", pipenum);
return;
}
nrf_base_address[4] = AddrByte;
nrf_pipe_addr[pipenum] = AddrByte;
if (pipenum == 0) {
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5);
}
else if (pipenum == 1) {
NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5);
}
else {
NRF_WriteRegister(RG_RX_ADDR_P2 + (pipenum - 2), AddrByte);
}
}
bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum)
{
for (uint8_t i = 0; i < 6; i++) {
if(!nrf_pipe_enabled[i]) {
NRF_SetRxAddress(i, AddrByte);
*PipeNum = i;
NRF_EnablePipe(i);
return true;
}
}
return false;
}
uint8_t NRF_PipeNum2Addr(uint8_t pipe_num)
{
if (pipe_num > 5) return 0; // fail
return nrf_pipe_addr[pipe_num];
}
uint8_t NRF_Addr2PipeNum(uint8_t addr)
{
for (int i = 0; i < 6; i++) {
if (nrf_pipe_addr[i] == addr) return (uint8_t) i;
}
return 0xFF;
}
void NRF_EnablePipe(uint8_t pipenum)
{
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
enabled |= 1 << pipenum;
NRF_WriteRegister(RG_EN_RXADDR, enabled);
nrf_pipe_enabled[pipenum] = 1;
}
void NRF_DisablePipe(uint8_t pipenum)
{
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
enabled &= ~(1 << pipenum);
NRF_WriteRegister(RG_EN_RXADDR, enabled);
nrf_pipe_enabled[pipenum] = 0;
}
static void NRF_SetTxAddress(uint8_t SendTo)
{
nrf_base_address[4] = SendTo;
NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5);
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0
}
void NRF_PowerDown(void)
{
CELOW;
NRF_WriteRegister(RG_CONFIG, ModeBits);
}
void NRF_ModeTX(void)
{
CELOW;
uint8_t m = NRF_ReadRegister(RG_CONFIG);
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP);
if ((m & RD_CONFIG_PWR_UP) == 0) LL_mDelay(5);
}
void NRF_ModeRX(void)
{
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX);
NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception
CEHIGH;
//if ((m&2)==0) LL_mDelay()(5); You don't need to wait. Just nothing will come for 5ms or more
}
uint8_t NRF_IsModePowerDown(void)
{
uint8_t ret = 0;
if ((NRF_ReadRegister(RG_CONFIG) & RD_CONFIG_PWR_UP) == 0) ret = 1;
return ret;
}
uint8_t NRF_IsModeTX(void)
{
uint8_t m = NRF_ReadRegister(RG_CONFIG);
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
if ((m & RD_CONFIG_PRIM_RX) == 0) return 1;
return 0;
}
uint8_t NRF_IsModeRx(void)
{
uint8_t m = NRF_ReadRegister(RG_CONFIG);
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
if ((m & RD_CONFIG_PRIM_RX) == 0) return 0;
return 1;
}
void NRF_SetChannel(uint8_t Ch)
{
NRF_WriteRegister(RG_RF_CH, Ch);
}
uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum)
{
uint8_t pw = 0, status;
if (!NRF_IsRxPacket()) return 0;
CELOW;
CHIPSELECT {
status = spi(CMD_RD_RX_PL_WIDTH);
pw = spi(0);
}
if (pw > 32) {
CHIPSELECT {
spi(CMD_FLUSH_RX);
}
NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR);
return 0;
}
// Read the reception pipe number
*PipeNum = (status & RD_STATUS_RX_PNO) >> 1;
CHIPSELECT {
spi(CMD_RD_RX_PLD);
for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0);
}
NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt
CEHIGH;
return pw;
}
bool NRF_IsRxPacket(void)
{
uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR;
return 0 != ret;
}
bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length)
{
if (!nrf_pipe_enabled[PipeNum]) {
dbg("!! Pipe %d not enabled", PipeNum);
return 0;
}
const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG);
CELOW;
NRF_ModeTX(); // Make sure in TX mode
NRF_SetTxAddress(nrf_pipe_addr[PipeNum]);
CHIPSELECT {
spi(CMD_FLUSH_TX);
};
CHIPSELECT {
spi(CMD_WR_TX_PLD);
for (uint8_t i = 0; i < Length; i++) spi(Packet[i]);
};
CEHIGH;
_delay_us(15); // At least 10 us
CELOW;
uint8_t st = 0;
while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) {
st = NRF_ReadStatus(); // Packet acked or timed out
}
NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit
if ((orig_conf & RD_CONFIG_PWR_UP) == 0) {
NRF_PowerDown();
}
else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) {
NRF_ModeRX();
}
return 0 != (st & RD_STATUS_TX_DS); // success
}
void NRF_Reset(void)
{
NSS(1);
CELOW;
NRF_PowerDown();
NRF_WriteRegister(RG_EN_RXADDR, 0); // disable all pipes
for (int i = 0; i < 6; i++) {
nrf_pipe_addr[i] = 0;
nrf_pipe_enabled[i] = 0;
}
}
void NRF_Init(uint8_t pSpeed)
{
// Set the required output pins
NSS(1);
CELOW;
LL_mDelay(200);
NRF_WriteRegister(RG_CONFIG, ModeBits);
NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses
// default
// NRF_EnablePipe(0);
NRF_WriteRegister(RG_SETUP_RETR, 0x18); // 8 retries
NRF_WriteRegister(RG_RF_CH, 2); // channel 2 NO HIGHER THAN 83 in USA!
NRF_WriteRegister(RG_RF_SETUP, pSpeed);
NRF_WriteRegister(RG_DYNPD, 0b111111); // Dynamic packet length
NRF_WriteRegister(RG_FEATURE, 0b100); // Enable dynamic payload, and no payload in the ack.
for (int i = 0; i < 6; i++) {
NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length
}
//NRFModePowerDown(); // Already in power down mode, dummy
}

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

@ -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

@ -49,7 +49,7 @@ void systemsettings_init(void)
void systemsettings_save(PayloadBuilder *pb)
{
pb_char(pb, 'S');
pb_u8(pb, 2); // settings format version
pb_u8(pb, 3); // settings format version
{ // system settings
pb_bool(pb, SystemSettings.visible_vcom);
@ -63,9 +63,52 @@ void systemsettings_save(PayloadBuilder *pb)
pb_bool(pb, SystemSettings.use_comm_lora);
pb_u32(pb, SystemSettings.comm_uart_baud);
pb_bool(pb, SystemSettings.enable_debug_uart);
// 3
pb_u8(pb, SystemSettings.nrf_channel);
pb_u8(pb, SystemSettings.nrf_address);
pb_buf(pb, SystemSettings.nrf_network, 4);
} // end system settings
}
// from binary
bool systemsettings_load(PayloadParser *pp)
{
if (pp_char(pp) != 'S') return false;
systemsettings_begin_load();
uint8_t version = pp_u8(pp);
{ // system settings
SystemSettings.visible_vcom = pp_bool(pp);
SystemSettings.ini_comments = pp_bool(pp);
// conditional fields based on version
if (version >= 1) {
SystemSettings.enable_mco = pp_bool(pp);
SystemSettings.mco_prediv = pp_u8(pp);
}
if (version >= 2) {
SystemSettings.use_comm_uart = pp_bool(pp);
SystemSettings.use_comm_nordic = pp_bool(pp);
SystemSettings.use_comm_lora = pp_bool(pp);
SystemSettings.comm_uart_baud = pp_u32(pp);
SystemSettings.enable_debug_uart = pp_bool(pp);
}
if (version >= 3) {
SystemSettings.nrf_channel = pp_u8(pp);
SystemSettings.nrf_address = pp_u8(pp);
pp_buf(pp, SystemSettings.nrf_network, 4);
}
} // end system settings
systemsettings_finalize_load();
return pp->ok;
}
void systemsettings_mco_teardown(void)
{
if (SystemSettings.enable_mco) {
@ -80,8 +123,7 @@ void systemsettings_mco_init(void)
assert_param(rsc_claim(&UNIT_SYSTEM, R_PA8) == E_SUCCESS);
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA8, LL_GPIO_AF_0));
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK,
SystemSettings.mco_prediv << RCC_CFGR_MCOPRE_Pos);
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, SystemSettings.mco_prediv << RCC_CFGR_MCOPRE_Pos);
} else {
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, 0);
}
@ -115,39 +157,6 @@ void systemsettings_finalize_load(void)
com_claim_resources_for_alt_transfers();
}
// from binary
bool systemsettings_load(PayloadParser *pp)
{
if (pp_char(pp) != 'S') return false;
systemsettings_begin_load();
uint8_t version = pp_u8(pp);
{ // system settings
SystemSettings.visible_vcom = pp_bool(pp);
SystemSettings.ini_comments = pp_bool(pp);
// conditional fields based on version
if (version >= 1) {
SystemSettings.enable_mco = pp_bool(pp);
SystemSettings.mco_prediv = pp_u8(pp);
}
if (version >= 2) {
SystemSettings.use_comm_uart = pp_bool(pp);
SystemSettings.use_comm_nordic = pp_bool(pp);
SystemSettings.use_comm_lora = pp_bool(pp);
SystemSettings.comm_uart_baud = pp_u32(pp);
SystemSettings.enable_debug_uart = pp_bool(pp);
}
} // end system settings
systemsettings_finalize_load();
return pp->ok;
}
/**
* Write system settings to INI (without section)
*/

@ -11,13 +11,17 @@
#include "gex_hooks.h"
#include "unit_registry.h"
#include "comm/interfaces.h"
#include "system_settings.h"
/**
* This is a systick callback for GEX application logic
*/
void GEX_MsTick(void)
{
com_iface_flush_buffer();
if (gActiveComport == COMPORT_USART) {
com_iface_flush_buffer();
}
TF_Tick(comm);
Indicator_Tick();
ureg_tick_units();
@ -28,6 +32,11 @@ void GEX_MsTick(void)
*/
void GEX_PreInit(void)
{
// this is a hack to make logging of the initial messages work
// it's problematic because we shouldn't even enable the debug uart if it's disabled in the system settings
// TODO move system settings load earlier and check the uart flag in advance
SystemSettings.enable_debug_uart = true;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();

@ -41,6 +41,9 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_TEST);
#endif
// EXTI are always available
rsc_free_range(NULL, R_EXTI0, R_EXTI15);
// --- platform specific resource releases and claims ---
#if defined(GEX_PLAT_F103_BLUEPILL)

@ -54,7 +54,19 @@ error_t DIn_init(Unit *unit)
// Claim all needed pins
TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins));
uint16_t mask = 1;
uint16_t mask;
// claim the needed EXTIs
mask = 1;
for (int i = 0; i < 16; i++, mask <<= 1) {
if (priv->pins & mask) {
if ((priv->trig_rise|priv->trig_fall) & mask) {
TRY(rsc_claim(unit, R_EXTI0+i));
}
}
}
mask = 1;
for (int i = 0; i < 16; i++, mask <<= 1) {
if (priv->pins & mask) {
uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc);

Loading…
Cancel
Save