I am programming with the nRF52840DKs. [Toolchain Manager: v1.3.0, IDE: Visual Studio Code (VSCode), SDK: ncs v2.6.0, window11 pro]
I am currently working on integrating 'NUS_peripheral' and 'SPIM'.
My goal: communicate with the ADC via SPIM and transmit the collected data via Bluetooth.
The initialization of both functions has been successful; however, I am uncertain about how to effectively manage the tasks between NUS_peripheral and SPIM.
Currently, I am attempting the following approach, but it is not yielding the desired results:
- SPIM communicates at regular intervals using a timer and PPI.
- BLE sends data by calling the
bt_nus_send()function within a separate thread.
Below is the main part of the code.
nrfx_spim_t spim1_inst = NRFX_SPIM_INSTANCE(SPIM_INST_IDX);
nrfx_timer_t timer1_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);
nrfx_gpiote_t gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX);
nrf_ppi_channel_t ppi_channel_spi_start;
nrf_ppi_channel_t ppi_channel_spi_end;
nrf_ppi_channel_t ppi_channel_spi_count;
#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
#define PRIORITY 7
void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) {
// LOG_INF("spim1_handler - %d", spi_counter);
if ((spi_counter == 29) || (spi_counter > 29 && (spi_counter % 18 == 11))) {
spim1_inst.p_reg->TXD.PTR = (uint32_t)spim_tx_buf_repeated[0];
}
if ( (spi_counter > 29) && (spi_counter % 1000 == 0)) {
spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_rx_buf_A[0];
spi_counter = 30;
}
spi_counter++;
if (spi_counter == 0) {
spi_counter = 30;
}
}
void timer0_handler(nrf_timer_event_t event_type, void * p_context){
}
void peripheral_setup(void){
//LOG_INF("main - peripheral_setup");
nrfx_err_t error;
(void)error;
/* GPIOTE Setting */
static const nrfx_gpiote_output_config_t output_config = {
.drive = NRF_GPIO_PIN_S0S1,
.input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
.pull = NRF_GPIO_PIN_NOPULL,
};
const nrfx_gpiote_task_config_t task_config = {
.task_ch = out_channel,
.polarity = NRF_GPIOTE_POLARITY_TOGGLE,
.init_val = NRF_GPIOTE_INITIAL_VALUE_HIGH,
};
error = nrfx_gpiote_output_configure(&gpiote_inst, SS_PIN_MASTER, &output_config, &task_config);
nrfx_gpiote_out_task_enable(&gpiote_inst, SS_PIN_MASTER);
/* SPIM 1 Setting */
nrfx_spim_config_t spim1_config = NRFX_SPIM_DEFAULT_CONFIG(SCK_PIN_MASTER,
MOSI_PIN_MASTER,
MISO_PIN_MASTER,
NRF_SPIM_PIN_NOT_CONNECTED);
spim1_config.frequency = NRFX_MHZ_TO_HZ(8);
error = nrfx_spim_init(&spim1_inst, &spim1_config, spim1_handler,0);
nrfx_spim_xfer_desc_t spim1_xfer_desc = NRFX_SPIM_XFER_TRX((uint8_t*)spim_tx_buf_initial, 2, (uint8_t*)spim_rx_buf_A, 2);
uint32_t spim1_flags = NRFX_SPIM_FLAG_HOLD_XFER | NRFX_SPIM_FLAG_REPEATED_XFER;
error = nrfx_spim_xfer(&spim1_inst, &spim1_xfer_desc, spim1_flags);
spim1_inst.p_reg->TXD.PTR = (uint32_t)spim_tx_buf_initial[0];
spim1_inst.p_reg->TXD.MAXCNT = 2;
spim1_inst.p_reg->TXD.LIST =SPIM_TXD_LIST_LIST_ArrayList << SPIM_TXD_LIST_LIST_Pos;
spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_rx_buf_A[0];
spim1_inst.p_reg->RXD.MAXCNT = 2;
spim1_inst.p_reg->RXD.LIST = SPIM_RXD_LIST_LIST_ArrayList << SPIM_RXD_LIST_LIST_Pos;
/* TIMER 0 Setting */
nrfx_timer_config_t timer0_config = NRFX_TIMER_DEFAULT_CONFIG(16000000);
timer0_config.bit_width = NRF_TIMER_BIT_WIDTH_32,
error = nrfx_timer_init(&timer1_inst, &timer0_config, timer0_handler);
nrfx_timer_clear(&timer1_inst);
k_sleep(K_MSEC(2000));
uint32_t desired_ticks = nrfx_timer_us_to_ticks(&timer1_inst, TIME_TO_WAIT_US);
nrfx_timer_extended_compare(&timer1_inst, NRF_TIMER_CC_CHANNEL0, desired_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
/* PPI Setting */
uint32_t gpiote_task_addr = nrfx_gpiote_out_task_address_get(&gpiote_inst ,SS_PIN_MASTER);
uint32_t timer_start_compare_event_addr = nrfx_timer_compare_event_address_get(&timer1_inst, NRF_TIMER_CC_CHANNEL0);
uint32_t spi_start_task_addr = nrfx_spim_start_task_address_get(&spim1_inst);
uint32_t spi_end_evt_addr = nrfx_spim_end_event_address_get(&spim1_inst);
// Timer reaches the desired tick -> GPIOTE toggle(off), SPI start
error = nrfx_gppi_channel_alloc(&ppi_channel_spi_start);
nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_start, timer_start_compare_event_addr, gpiote_task_addr);
nrfx_gppi_fork_endpoint_setup(ppi_channel_spi_start, spi_start_task_addr);
// SPI tx-rx transmission ends -> GPIOTE toggle(on)
error = nrfx_gppi_channel_alloc(&ppi_channel_spi_end);
nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_end, spi_end_evt_addr, gpiote_task_addr);
}
int main(void){
nrfx_err_t status;
(void)status;
int err;
initialization_command();
bt_conn_cb_register(&conn_callbacks);
err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
LOG_INF("main - bt_conn_auth_info_cb_register: %d",err);
err = bt_enable(NULL);
LOG_INF("main - bt_enable: %d",err);
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
err = bt_nus_init(&nus_cb);
err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
k_sem_take(¶m_ok, K_FOREVER);
k_sem_take(&data_length_ok, K_FOREVER);
k_sem_take(&phy_ok, K_FOREVER);
/************ SPIM ************/
#if defined(__ZEPHYR__)
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPIM_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_SPIM_INST_HANDLER_GET(SPIM_INST_IDX), 0, 0);
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0, 0);
#endif
status = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
LOG_INF("main - nrfx_gpiote_init: %d", status);
status = nrfx_gpiote_channel_alloc(&gpiote_inst, &out_channel);
LOG_INF("main - nrfx_gpiote_channel_alloc: %d", status);
peripheral_setup();
LOG_INF(" spim_rx_buf_A[0][0]: %p", (void*)&spim_rx_buf_A[0][0]);
LOG_INF(" spim_rx_buf_A[%d][0]: %p",rx_data_size-1, (void*)&spim_rx_buf_A[rx_data_size-1][0]);
nrfx_gpiote_out_task_enable(&gpiote_inst, SS_PIN_MASTER);
nrfx_gppi_channels_enable(BIT(ppi_channel_spi_start));
nrfx_gppi_channels_enable(BIT(ppi_channel_spi_end));
nrfx_timer_enable(&timer1_inst);
k_sem_give(&nus_start);
return 0;
}
void ble_write_thread(void){
int ret;
k_sem_take(&nus_start, K_FOREVER);
LOG_INF("Starting BLE Write Thread");
while (1) {
ret = bt_nus_send(current_conn, data_to_central, MTU_SIZE);
LOG_INF("bt_nus_send: %d", ret);
if (k_sem_take(&disconnect_sem, K_NO_WAIT) == 0){
LOG_INF("Disconnected, exiting BLE Write Thread");
return;
}
}
}
K_THREAD_DEFINE(ble_write_thread_id, 1024, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);