Hello,
I am programming BLE with the nRF52840-DK. [Toolchain Manager: v1.3.0, IDE: Visual Studio Code (VSCode), SDK: ncs v2.6.0, window11 pro]
< Simple Code Explanation >
1. The ADC (SLAVE) and nRF52840 DK (MASTER) communicate via SPIM.
2. A command is sent to the ADC at regular intervals defined by 'TIME_TO_WAIT_US'.
- The TIMER is used to measure the intervals and PPI is used to start SPIM.
- The command buffer includes
tx_buf_array
andtx_buf_array_2
. (nRF52840 DK -> ADC) tx_buf_array
is a command for ADC initialization.tx_buf_array_2
is a command to retrieve ADC data and is intended to be sent repeatedly.- The SPIM handler exists to modify
Tx_PTR
and to signal the end of SPIM. - The TIMER handler exists to signal the end of the TIMER.
< my issue>
If TIME_TO_WAIT_US is less than 10, SPIM communication does not work properly. (ADC spec: Maximum SCLK frequency is 25 MHz)
I think a lot of time is being consumed in the handler. I'm not sure exactly what the problem is.
I want SPIM to work properly when 'TIME_TO_WAIT_US' is 5~6.
Could you give me some advice?
- Below is my code for the handler part:void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) {
//LOG_INF("spim1_handler[%d] - TXD.PTR: 0x%08X", spi_counter, spim1_inst.p_reg->TXD.PTR);
if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array_2[17] + 2) {
spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0];
} else if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array[30] ) {
spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0];
}
if(spi_counter == MAX_SPI_COUNT){
spi_disable(spim1_inst.p_reg);
k_sem_give(&sem_condition1);
}
spi_counter++;
}
void timer0_handler(nrf_timer_event_t event_type, void * p_context){
if(spi_counter == MAX_SPI_COUNT){
timer_disable(&timer0_inst);
k_sem_give(&sem_condition2);
}
}
- Below is my code for the ppi part:
/* 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(&timer0_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);
- below is my 'main.c' code:
#include <nrfx_example.h> #include <nrfx_spim.h> #include <nrfx_timer.h> #include <helpers/nrfx_gppi.h> #include <nrfx_gpiote.h> #include <cho_intan_RHD2132.h> #include <zephyr/logging/log.h> #include <stdlib.h> #define LOG_MODULE_NAME cho LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); // Pin definitions #define MISO_PIN_MASTER 29 #define MOSI_PIN_MASTER 28 #define SCK_PIN_MASTER 4 #define SS_PIN_MASTER 3 // Peripheral instance indexes #define SPIM_INST_IDX 1 #define TIMER_INST_IDX 0 #define GPIOTE_INST_IDX 0 // Peripheral instances nrfx_spim_t spim1_inst = NRFX_SPIM_INSTANCE(SPIM_INST_IDX); nrfx_timer_t timer0_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX); nrfx_gpiote_t gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX); // PPI channels nrf_ppi_channel_t ppi_channel_spi_start; nrf_ppi_channel_t ppi_channel_spi_end; nrf_ppi_channel_t ppi_channel_spi_count; // Counters and flags volatile int timer_counter = 0; volatile int spi_counter = 0; volatile bool stop = false; volatile bool sample_on = false; // Semaphores static K_SEM_DEFINE(sem_condition1, 0, 1); static K_SEM_DEFINE(sem_condition2, 0, 1); // INTAN RHD2132 related settings #define MAX_SPI_COUNT 138 #define TIME_TO_WAIT_US 12 #define ROUND(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x) - 0.5)) #define total_sampling_rate ROUND(1000000.0 / TIME_TO_WAIT_US) #define N_Channel 16 #define N_Aux_command 2 #define per_ch_SAMPLE_RATE (total_sampling_rate /(N_Channel + N_Aux_command)) double lower_bandwidth = 1; int upper_bandwidth = 300; uint16_t registers[18]; // RHD configuration structure RHDConfigParameters RHD_config; RHDConfigParameters* RHD_p = &RHD_config; // Buffer arrays uint8_t tx_buf_array[30][2]; uint8_t tx_buf_array_2[18][2]; uint8_t rx_buf_array[2048][2]; // GPIOTE related uint8_t out_channel; void spi_disable(NRF_SPIM_Type *p_spim_instance) { nrfy_spim_disable(p_spim_instance); nrf_spim_int_disable(p_spim_instance, 0xFFFFFFFF); } void timer_disable(nrfx_timer_t *p_timer_instance) { nrfx_timer_disable(p_timer_instance); nrfx_timer_uninit(p_timer_instance); } void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) { //LOG_INF("spim1_handler[%d] - TXD.PTR: 0x%08X", spi_counter, spim1_inst.p_reg->TXD.PTR); if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array_2[17] + 2) { spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0]; } else if(spim1_inst.p_reg->TXD.PTR == (uint32_t)&tx_buf_array[30] ) { spim1_inst.p_reg->TXD.PTR = (uint32_t)tx_buf_array_2[0]; } if(spi_counter == MAX_SPI_COUNT){ spi_disable(spim1_inst.p_reg); k_sem_give(&sem_condition1); } spi_counter++; } void timer0_handler(nrf_timer_event_t event_type, void * p_context){ if(spi_counter == MAX_SPI_COUNT){ timer_disable(&timer0_inst); k_sem_give(&sem_condition2); } } // GPIOTE, SPIM, TIMER, PPI etc.. 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*)tx_buf_array, 2, (uint8_t*)rx_buf_array, 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)tx_buf_array[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)rx_buf_array[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(&timer0_inst, &timer0_config, timer0_handler); nrfx_timer_clear(&timer0_inst); uint32_t desired_ticks = nrfx_timer_us_to_ticks(&timer0_inst, TIME_TO_WAIT_US); nrfx_timer_extended_compare(&timer0_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(&timer0_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); } void set_default_rhd_settings(RHDConfigParameters* p){ // Reg 0 p->adc_reference_bw = 3; p->amp_fast_settle = 0; p->amp_vref_enable = 1; p->adc_comparator_bias = 3; p->adc_comparator_select = 2; // Reg 1~2 p->vdd_sense_enable = 0; set_ADCbufferbias_MUXbias(p, total_sampling_rate); // Reg 3 p->mux_load = 0; p->temp_S1 = 0; p->temp_S2 = 0; p->temp_en = 0; p->digOut = 0; p->digOut_hiZ = 1; // Reg 4 DSP 수정 p->weak_miso = 1; p->twos_comp = 0; p->abs_mode = 0; p->DSP_en = 0; set_DSP_cutoff_freq(p, 5.0); // p->DSP_cutoff_freq = DSP cutoff freq 인덱스 저장 // Reg 5 p->zcheck_DAC_power = 0; p->zcheck_load = 0; p->zcheck_scale = 0x00; p->zcheck_conn_all = 0; p->zcheck_sel_pol = 0 ; p->zcheck_en = 0; // Reg 6~7 Zcheck DAC는 get_register_value 함수에 존재 p->zcheck_select = 0; // Reg 8~13 upper: 300Hz Lower:1Hz p->off_chip_RH1 = 0; p->off_chip_RH2 = 0; p->off_chip_RL = 0; p->adc_Aux1_en = 0; p->adc_Aux2_en = 0; p->adc_Aux3_en = 0; set_bandwidthREG(p, upper_bandwidth, lower_bandwidth); // Reg 14~17 for (int channel = 0; channel < N_Channel; ++channel) { p->amp_pwr[channel] = 1; } for (int channel = N_Channel; channel < 32; ++channel) { p->amp_pwr[channel] = 0; } } void initialization_command(){ RHD_p->sample_rate = per_ch_SAMPLE_RATE; set_default_rhd_settings(RHD_p); for (int i = 0; i < 18; i++) { registers[i] = get_register_value(RHD_p, i); } tx_buf_array[0][0] = upper_8bit(read_command(63)); // Read(63) = 0xFF00 tx_buf_array[0][1] = lower_8bit(read_command(63)); tx_buf_array[1][0] = upper_8bit(read_command(63)); // Read(63) = 0xFF00 tx_buf_array[1][1] = lower_8bit(read_command(63)); for (int i = 2; i < 20; i++) { // Write() tx_buf_array[i][0] = upper_8bit(write_command(i-2, registers[i-2])); tx_buf_array[i][1] = lower_8bit(write_command(i-2, registers[i-2])); } tx_buf_array[20][0] = upper_8bit(calibrate_command()); //Calibrate() = 0x5500 tx_buf_array[20][1] = lower_8bit(calibrate_command()); for (int i = 21; i < 30; i++) { // Read(63) = 0xFF00 tx_buf_array[i][0] = upper_8bit(read_command(63)); tx_buf_array[i][1] = lower_8bit(read_command(63)); } for (int i = 0; i < 16 ; i++){ tx_buf_array_2[i][0] = upper_8bit(convert_command(i, 0)); tx_buf_array_2[i][1] = lower_8bit(convert_command(i, 0)); } tx_buf_array_2[16][0] = upper_8bit(read_command(63)); tx_buf_array_2[16][1] = lower_8bit(read_command(63)); tx_buf_array_2[17][0] = upper_8bit(read_command(63)); tx_buf_array_2[17][1] = lower_8bit(read_command(63)); } int main(void){ nrfx_err_t status; (void)status; uint16_t combined_value; // Initialize Command to send to the ADC initialization_command(); #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 LOG_INF(" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "); LOG_INF("main - TIME_TO_WAIT_US: %d [us]", TIME_TO_WAIT_US); LOG_INF("main - total_sampling_rate: %ld [Hz]", total_sampling_rate); LOG_INF("main - per_ch_SAMPLE_RATE: %ld [Hz]", per_ch_SAMPLE_RATE); k_sleep(K_MSEC(100)); status = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY); //LOG_INF("GPIOTE status: %s", nrfx_gpiote_init_check(&gpiote_inst) ? "initialized" : "not initialized"); status = nrfx_gpiote_channel_alloc(&gpiote_inst, &out_channel); LOG_INF("main - tx_buf_array[0]: %p", (void*)&tx_buf_array[0][0]); LOG_INF("main - tx_buf_array[29]: %p", (void*)&tx_buf_array[29][0]); LOG_PROCESS(); k_sleep(K_MSEC(1000)); LOG_INF("main - tx_buf_array_2[0]: %p", (void*)&tx_buf_array_2[0][0]); LOG_INF("main - tx_buf_array_2[29]: %p", (void*)&tx_buf_array_2[17][0]); LOG_PROCESS(); k_sleep(K_MSEC(1000)); peripheral_setup(); LOG_INF("main - peripheral_setup"); 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(&timer0_inst); LOG_INF("main - nrfx_timer_enable"); k_sem_take(&sem_condition1, K_FOREVER); k_sem_take(&sem_condition2, K_FOREVER); LOG_INF("main - k_sem_take"); for (int t = -2; t < MAX_SPI_COUNT; t++) { LOG_INF(" %d >>>> rx: 0x%02x%02x", t, rx_buf_array[t+2][0], rx_buf_array[t+2][1]); LOG_PROCESS(); } int32_t voltage_uV; int32_t voltage_whole; int32_t voltage_frac; for (int t = 30; t < MAX_SPI_COUNT; t++){ combined_value = (uint16_t)((rx_buf_array[t][0] << 8) | rx_buf_array[t][1]); voltage_uV = (int32_t)(0.195 * (combined_value - 32768)); voltage_whole = voltage_uV / 1000; voltage_frac = abs(voltage_uV % 1000); LOG_INF(" index:%d >>> %d.%03d [mV]", t, voltage_whole, voltage_frac); } LOG_INF("spim>> %d", spi_counter); LOG_INF(" MAIN END"); return 0; }