SENT protocol based sensor configuration with nrf boards

hey there, i have a project which uses  nrf9151 with a pressures sensor from BOSCH which uses SENT protocol to transfer data, my question is

1. Is it possible to configure the SENT protocol on the nrf9151
2. if yes, how am i gonna configure what should i use?

Parents
  • #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <nrfx_gpiote.h>
    #include <nrfx_timer.h>
    #include <nrfx_ppi.h>
    #include <zephyr/sys/printk.h>

    #define SENT_GPIO_PIN 11 // Replace with your actual GPIO pin number

    nrfx_timer_t timer = NRFX_TIMER_INSTANCE(0);
    static uint32_t pulse_buffer[64];
    static uint8_t pulse_index = 0;
    static uint32_t last_capture = 0;
    static uint8_t last_printed_index = 0;

    void gpio_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t trigger, void *p_context)
    {
    uint32_t capture_value = nrf_timer_cc_get(timer.p_reg, NRF_TIMER_CC_CHANNEL0);
    uint32_t pulse_width = capture_value - last_capture;
    last_capture = capture_value;
    pulse_buffer[pulse_index] = pulse_width;
    pulse_index = (pulse_index + 1) % 64;
    }

    void timer_handler(nrf_timer_event_t event_type, void *p_context)
    {
    }

    int main()
    {
    printk("Starting pressure sensor example\n\r");
    int err_code;
    if (!nrfx_gpiote_is_init())
    {
    err_code = nrfx_gpiote_init(0);
    }
    uint8_t gpiote_channel_index;
    err_code = nrfx_gpiote_channel_alloc(&gpiote_channel_index);
    if (err_code != NRFX_SUCCESS)
    {
    printk("Failed to allocate GPIOTE channel. Error code: %d\n", err_code);
    return -1;
    }

    nrfx_gpiote_input_config_t input_config = {
    .pull = NRF_GPIO_PIN_PULLUP};

    nrfx_gpiote_trigger_config_t trigger_config = {
    .trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
    .p_in_channel = &gpiote_channel_index};

    nrfx_gpiote_handler_config_t handler_config = {
    .handler = gpio_handler,
    .p_context = NULL};

    err_code = nrfx_gpiote_input_configure(SENT_GPIO_PIN, &input_config, &trigger_config, &handler_config);
    if (err_code != NRFX_SUCCESS)
    {
    printk("GPIOTE input configuration failed with error code: %d\n", err_code);
    return -1;
    }
    printk("GPIOTE configured for pin %d, channel %d\n", SENT_GPIO_PIN, gpiote_channel_index);
    uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer.p_reg);
    printk("Frequency is %d\n\r", base_frequency);
    nrfx_timer_config_t config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
    config.mode = NRF_TIMER_MODE_TIMER;
    config.bit_width = NRF_TIMER_BIT_WIDTH_32;
    config.p_context = &timer;
    err_code = nrfx_timer_init(&timer, &config, timer_handler);
    if (err_code != NRFX_SUCCESS)
    {
    printk("Timer initialization failed. Error code: %d\n", err_code);
    return -1;
    }

    // Configure timer to clear on every 3µs (assuming 16MHz timer frequency)
    // nrf_timer_cc_set(timer.p_reg, NRF_TIMER_CC_CHANNEL1, 16 * 3);
    // nrf_timer_shorts_enable(timer.p_reg, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK);

    // Enable Timer
    nrfx_timer_enable(&timer);

    // nrf_timer_cc_set(timer.p_reg, NRF_TIMER_CC_CHANNEL0, 16000000); // 1 second interval
    // nrf_timer_shorts_enable(timer.p_reg, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);
    nrf_timer_int_enable(timer.p_reg, NRF_TIMER_INT_COMPARE0_MASK);
    nrfx_gpiote_trigger_enable(SENT_GPIO_PIN, true);

    // Configure PPI
    nrf_ppi_channel_t ppi_channel;
    err_code = nrfx_ppi_channel_alloc(&ppi_channel);
    if (err_code != NRFX_SUCCESS)
    {
    printk("PPI channel allocation failed with error code: %d\n", err_code);
    return -1;
    }

    printk("PPI channel allocated\n\r");

    // Set up the event endpoint
    nrf_gpiote_event_t gpiote_event = nrf_gpiote_event_pin_get(NRF_GPIOTE, gpiote_channel_index);
    uint32_t gpiote_event_addr = nrf_gpiote_event_address_get(NRF_GPIOTE, gpiote_event);

    // Set up the task endpoint
    nrf_timer_task_t timer_task = NRF_TIMER_TASK_CAPTURE0;
    uint32_t timer_task_addr = nrf_timer_task_address_get(timer.p_reg, timer_task);

    // Connect the event and task using PPI
    err_code = nrfx_ppi_channel_assign(ppi_channel, gpiote_event_addr, timer_task_addr);
    if (err_code != NRFX_SUCCESS)
    {
    printk("PPI channel assignment failed with error code: %d\n", err_code);
    return -1;
    }

    printk("PPI channel assigned\n\r");

    // Enable the PPI channel
    err_code = nrfx_ppi_channel_enable(ppi_channel);
    if (err_code != NRFX_SUCCESS)
    {
    printk("PPI channel enable failed with error code: %d\n", err_code);
    return -1;
    }

    printk("PPI channel enabled\n\r");

    // Enable GPIOTE interrupt

    printk("GPIOTE Event Address: 0x%08X\n\r", gpiote_event_addr);
    printk("Timer Task Address: 0x%08X\n\r", timer_task_addr);

    while (1)
    {
    printk("Pulse %d: %u ticks\n\r", last_printed_index, pulse_buffer[last_printed_index]);
    last_printed_index = (last_printed_index + 1) % 64;
    k_sleep(K_MSEC(1000));
    }
    }
  • Something like this may work. What will happen is that it will automatically capture the TIMER value when the GPIO event triggers, that you can then read out in the gpio_handler, as you do. The issue is that you are dependent of the CPU to store away the buffer using the gpio_handler(). If the CPU is busy handling something else, only for a short time, that is fine, because the gpio_handler() will be called when that initial task is done. But if the CPU is busy for a bit longer, or two of the pulses are really close to eachother, then you risk not being able to handle the first interrupt before the second one occurs, and you risk that your application interprets two pulses as one that is the sum of the two (because the PPI task will trigger everytime. It doesn't know whether you have had time to update the last_capture parameter yet or not).

    I don't know at what rates these pulses come. What is the shortest possible pulse? If you want to try this, I suggest that you set the gpio_handler priority very high. 

    Best regards,

    Edvin

  • Hi,

    thank you for clearing it out,

    regarding your questions, the measuring unit is Tick and 1 tick Minimum is 3us and the Minimum pulse time can be 12 Ticks which is 36us.

  • That sounds very fast, so not sure this would work. It would be difficult to guarantee that you have access to the CPU every 3µs. What if you get any other interrupts, e.g. from the modem. Even without any other interrupts, I don't know if your handler will be able to finish within the 3µs (in case you get two 0x0 in a row).

    Best regards,

    Edvin

Reply
  • That sounds very fast, so not sure this would work. It would be difficult to guarantee that you have access to the CPU every 3µs. What if you get any other interrupts, e.g. from the modem. Even without any other interrupts, I don't know if your handler will be able to finish within the 3µs (in case you get two 0x0 in a row).

    Best regards,

    Edvin

Children
No Data
Related