184 lines
5.3 KiB
C
184 lines
5.3 KiB
C
/*******************************************************************************
|
|
* @file spi2_bus.c
|
|
* @brief Shared SPI2 Bus - nrfx_spim driver (SoftDevice safe)
|
|
* @author Charles KWON <charleskwon@medithings.co.kr>
|
|
* @date 2025-02-03
|
|
*
|
|
* @note Uses nrfx_spim with APP_IRQ_PRIORITY_LOWEST for SoftDevice compatibility
|
|
******************************************************************************/
|
|
|
|
#include "spi2_bus.h"
|
|
#include "nrfx_spim.h"
|
|
#include "nrf_gpio.h"
|
|
#include "nrf_delay.h"
|
|
#include "app_error.h"
|
|
#include "app_util_platform.h" /* For APP_IRQ_PRIORITY_LOWEST */
|
|
#include "debug_print.h"
|
|
#include <stdio.h>
|
|
|
|
/* Define instance index if not provided by nrfx (SDK version dependent) */
|
|
#ifndef NRFX_SPIM2_INST_IDX
|
|
#define NRFX_SPIM2_INST_IDX 0
|
|
#endif
|
|
|
|
/*==============================================================================
|
|
* PRIVATE VARIABLES
|
|
*============================================================================*/
|
|
|
|
static bool m_initialized = false;
|
|
static nrfx_spim_t m_spi = NRFX_SPIM_INSTANCE(SPI2_BUS_INSTANCE);
|
|
|
|
/*==============================================================================
|
|
* PUBLIC FUNCTIONS
|
|
*============================================================================*/
|
|
|
|
ret_code_t spi2_bus_init(void)
|
|
{
|
|
if (m_initialized)
|
|
{
|
|
return NRF_SUCCESS;
|
|
}
|
|
|
|
DBG_PRINTF("[SPI2] nrfx init...\r\n");
|
|
|
|
nrfx_spim_config_t cfg = NRFX_SPIM_DEFAULT_CONFIG;
|
|
cfg.sck_pin = SPI2_SCK_PIN;
|
|
cfg.mosi_pin = SPI2_MOSI_PIN;
|
|
cfg.miso_pin = SPI2_MISO_PIN;
|
|
cfg.ss_pin = NRFX_SPIM_PIN_NOT_USED; /* Manual CS control */
|
|
cfg.frequency = NRF_SPIM_FREQ_1M; /* Try slower for debugging */
|
|
cfg.mode = NRF_SPIM_MODE_0;
|
|
cfg.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST;
|
|
cfg.irq_priority = APP_IRQ_PRIORITY_LOWEST; /* SoftDevice safe! */
|
|
|
|
/* Use NULL handler for blocking mode (no IRQ needed) */
|
|
nrfx_err_t err = nrfx_spim_init(&m_spi, &cfg, NULL, NULL);
|
|
DBG_PRINTF("[SPI2] init err=%d (blocking)\r\n", err);
|
|
|
|
if (err != NRFX_SUCCESS && err != NRFX_ERROR_INVALID_STATE) {
|
|
DBG_PRINTF("[SPI2] FAIL!\r\n");
|
|
return err;
|
|
}
|
|
|
|
/* Configure CS pins as outputs, deasserted (high) */
|
|
nrf_gpio_cfg_output(SPI2_CS_ADA2200);
|
|
nrf_gpio_cfg_output(SPI2_CS_FLASH);
|
|
nrf_gpio_pin_set(SPI2_CS_ADA2200);
|
|
nrf_gpio_pin_set(SPI2_CS_FLASH);
|
|
|
|
m_initialized = true;
|
|
DBG_PRINTF("[SPI2] OK\r\n");
|
|
|
|
return NRF_SUCCESS;
|
|
}
|
|
|
|
void spi2_bus_uninit(void)
|
|
{
|
|
if (!m_initialized) return;
|
|
|
|
nrfx_spim_uninit(&m_spi);
|
|
|
|
nrf_gpio_cfg_default(SPI2_SCK_PIN);
|
|
nrf_gpio_cfg_default(SPI2_MISO_PIN);
|
|
nrf_gpio_cfg_default(SPI2_MOSI_PIN);
|
|
nrf_gpio_cfg_default(SPI2_CS_ADA2200);
|
|
nrf_gpio_cfg_default(SPI2_CS_FLASH);
|
|
|
|
m_initialized = false;
|
|
}
|
|
|
|
bool spi2_bus_is_initialized(void)
|
|
{
|
|
return m_initialized;
|
|
}
|
|
|
|
const nrf_drv_spi_t* spi2_bus_get_instance(void)
|
|
{
|
|
/* Using nrfx_spim now - return NULL for legacy compatibility */
|
|
return NULL;
|
|
}
|
|
|
|
/* Debug: count transfers for selective logging */
|
|
static uint32_t s_xfer_count = 0;
|
|
|
|
ret_code_t spi2_bus_transfer(const uint8_t *tx_buf, uint8_t tx_len,
|
|
uint8_t *rx_buf, uint8_t rx_len)
|
|
{
|
|
if (!m_initialized)
|
|
{
|
|
DBG_PRINTF("[SPI2] ERROR: not init!\r\n");
|
|
return NRF_ERROR_INVALID_STATE;
|
|
}
|
|
|
|
s_xfer_count++;
|
|
bool debug = (s_xfer_count <= 10);
|
|
|
|
nrfx_spim_xfer_desc_t xfer;
|
|
nrfx_err_t err;
|
|
|
|
/* Blocking mode: nrfx_spim_xfer() waits for completion internally */
|
|
|
|
/* Full-duplex mode: TX and RX simultaneously */
|
|
if (tx_len > 0 && rx_len > 0) {
|
|
DBG_PRINTF("[SPI2] FD TX[%d] RX[%d]\r\n", tx_len, rx_len);
|
|
|
|
xfer.p_tx_buffer = tx_buf;
|
|
xfer.tx_length = tx_len;
|
|
xfer.p_rx_buffer = rx_buf;
|
|
xfer.rx_length = rx_len;
|
|
|
|
DBG_PRINTF("[SPI2] xfer...\r\n");
|
|
err = nrfx_spim_xfer(&m_spi, &xfer, 0);
|
|
DBG_PRINTF("[SPI2] xfer done err=%d\r\n", err);
|
|
if (err != NRFX_SUCCESS) {
|
|
DBG_PRINTF("[SPI2] FD err=%d\r\n", err);
|
|
return err;
|
|
}
|
|
|
|
DBG_PRINTF("[SPI2] RX: %02X %02X %02X %02X\r\n",
|
|
rx_buf[0],
|
|
rx_len > 1 ? rx_buf[1] : 0,
|
|
rx_len > 2 ? rx_buf[2] : 0,
|
|
rx_len > 3 ? rx_buf[3] : 0);
|
|
}
|
|
/* TX only mode */
|
|
else if (tx_len > 0) {
|
|
if (debug) {
|
|
DBG_PRINTF("[SPI2] TX[%d]: %02X\r\n", tx_len, tx_buf[0]);
|
|
}
|
|
|
|
xfer.p_tx_buffer = tx_buf;
|
|
xfer.tx_length = tx_len;
|
|
xfer.p_rx_buffer = NULL;
|
|
xfer.rx_length = 0;
|
|
|
|
err = nrfx_spim_xfer(&m_spi, &xfer, 0);
|
|
if (err != NRFX_SUCCESS) {
|
|
DBG_PRINTF("[SPI2] TX err=%d\r\n", err);
|
|
return err;
|
|
}
|
|
}
|
|
/* RX only mode */
|
|
else if (rx_len > 0) {
|
|
xfer.p_tx_buffer = NULL;
|
|
xfer.tx_length = 0;
|
|
xfer.p_rx_buffer = rx_buf;
|
|
xfer.rx_length = rx_len;
|
|
|
|
err = nrfx_spim_xfer(&m_spi, &xfer, 0);
|
|
if (err != NRFX_SUCCESS) {
|
|
DBG_PRINTF("[SPI2] RX err=%d\r\n", err);
|
|
return err;
|
|
}
|
|
|
|
if (debug) {
|
|
DBG_PRINTF("[SPI2] RX[%d]: %02X %02X %02X\r\n",
|
|
rx_len, rx_buf[0],
|
|
rx_len > 1 ? rx_buf[1] : 0,
|
|
rx_len > 2 ? rx_buf[2] : 0);
|
|
}
|
|
}
|
|
|
|
return NRF_SUCCESS;
|
|
}
|