/******************************************************************************* * @file spi2_bus.c * @brief Shared SPI2 Bus - nrfx_spim driver (SoftDevice safe) * @author Charles KWON * @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 /* 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; }