This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SPI doesn't work when started by Timer

Short: Working Timer. Working SPI. SPI does not work when triggered by timer_handler.

Hello,

I am currently trying to replace delays with timer in my code...

I set up a working timer that goes off every 4 seconds. In the handler that is called I would like to call the function that initiates a measurement and then gets the values afterwards. It does not work in combination. Debugger stops at if (p_spi_instance->disable_all_irq) in the SPI routine. (Flag is not set btw).

If I log via UART instead of any value it only outputs 0.

main.c

//Edit:

static void test_timer_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
		printf("Hallo\n");
		hole_temperatur();
}

When I call this function from within the timer handler:

        static int32_t hole_temperatur(void)
    {
    				
    					if (m_transfer_completed) 
    				{	// ADC Temperatur 256 Aufloesung
    					m_transfer_completed = false;	
    					m_tx_data_1B[0] = 0x50; 
    					uint32_t err_code = spi_master_send_recv(SPI_MASTER_0, m_tx_data_1B, 1, m_rx_data_1B, 1);
APP_ERROR_CHECK(err_code);	
    					printf("%d %X %d \n",err_code, m_rx_data_1B[0], m_transfer_completed);
    					nrf_delay_ms(1);
    				}
    				
    					if (m_transfer_completed)
            { //Hole und berechne Temperatur
              m_transfer_completed = false;					
    					m_tx_data_4B[0] = 0x00;
    					m_tx_data_4B[1] = 0xFF;
    					m_tx_data_4B[2] = 0xFF;
    					m_tx_data_4B[3] = 0xFF;
    					uint32_t err_code = spi_master_send_recv(SPI_MASTER_0, m_tx_data_4B, 4, m_rx_data_4B, 4);	
    					APP_ERROR_CHECK(err_code);	
    					printf("%d \n",err_code);
    					nrf_delay_ms(1);
    					printf("%X \n",m_rx_data_4B[1]);
    					//printf("%X \n",m_rx_data_4B[2]);
    					//printf("%X \n",m_rx_data_4B[3]);
    					D2 = m_rx_data_4B[1]<<16 | m_rx_data_4B[2]<<8 | m_rx_data_4B[3];
    					//printf("%d \n",D2);
    					//printf("%s \n", m_transfer_completed ? "true" : "false");
    					dT = (int32_t)D2 - ( (int32_t)Koeff[5] * 256 );				
    					T = 2000 + ((int64_t)dT * Koeff[6]) / 8388608LL;					
    				} return T = (int32_t)T;
    }

It outputs "0 FE 0" So no error. Expected Read Result but transfer not completed! I removed the static from the variable declaration but that didn't help. The flag is meant to be set inside the spi_master_event_handler.

When I remove the if(transfer_completed) from the //Hole und berechne Part I only receive a capital H every 4 seconds. (The "Hallo" is also gone missing)

Well it looks like it is the H from Hallo. With the hallo-printf statement excluded I aint got nothin'.

How else could I realize this? All I could think of is just setting a flag in the timer_handler and check for this in the main()-loop and then execute the code from here. But that wouldn't help me with current consumption, would it? This would also keep the chip awake or would this be better than using delay?

timer_handler {test_flag=true}

    for (;;)
    {
      power_manage();       
            if(test_flag) { printf("%d \n",hole_temperatur()); test_flag=false;}
}
  • Hi muhkuhns, I just checked and executed your code on S110 with SDK8.0 and found that there are no hardfaults if you do not break the execution by adding breakpoints. your print is sending zero probably because that is probably what SPI read from the sensor. you are doing spi_master_send_recv from interrupt context and there have been posts that it does not work well within interrupt context.

  • @RK: Thank you for this helpful explanations regarding debugging! I will take good use of them! I let the debugger run to the breakpoint@the call in the handler and then stepped lines (F11). Will look where I land after hitting break. Eh. Where is the "break" button?

    @Aryan: Thanks for looking into the code! I was afraid it was to due the execution within an interrupt context.. But I have no clue what my alternatives are. I simply want the measurements to take place every 4 seconds, but of course have the chip consume as less current as possible in between. What is recommended for this case? (Later on it would be even better if it starts the measurement ~3,8seconds after the values got read by the central)

  • Two more things I noticed while having a quick look into SPI driver

    1)spi_open() function sets priority of SPI interrupt and it takes the value from spi_config->SPI_PriorityIRQ. If you are not setting this then your SPI interrupt handler will be running either with random number that was present in this uninitialized local variable.

    1. I saw that there is a static function spi_master_send_recv_irq, which seems to be have designed for working within interrupt handler. You can remove the static and make it available for your application and try it.
  • @Aryan: To point 1.) 0 /**< Don't disable all IRQs. */ I used the macro for default values but I also tried it with 1 instead of 0.

    2.) I could swear it did jumped already into the spi_master_send_recv_irq when I last debugged it. I will have a look again.

    1. using macro is ok, i missed to see that.

    2. spi_master_send_recv_irq is used within SPI driver for SPI interrupt. You are anyways using spi_master_send_recv function in hole_temperature inside test_timer_handler. Instead of using spi_master_send_recv you can replace it with spi_master_send_recv_irq

Related