SPI communication using DPPI i wanna control cs pins as specific period. but cs pin is doesn't move at all.

/dts-v1/;
#include <nordic/nrf5340_cpuapp_qkaa.dtsi>
#include "bridge_wifi_nrf5340-pinctrl.dtsi"
#include "nrf5340_cpuapp_common.dtsi"

/ {
	model = "Nordic NRF7002 DK NRF5340 Application";
	compatible = "nordic,nrf7002-dk-nrf5340-cpuapp";

	chosen {
		zephyr,sram = &sram0_image;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,sram-secure-partition = &sram0_s;
		zephyr,sram-non-secure-partition = &sram0_ns;
		zephyr,wifi = &wlan0;
	};
};
#include "bridge_wifi_nrf5340-cpuapp_partitioning.dtsi"
#include "bridge_wifi_nrf5340-shared_sram.dtsi"

&qspi {
	nrf70: nrf7002@1 {
		compatible = "nordic,nrf7002-qspi";
		status = "okay";
		reg = <1>;
		qspi-frequency = <24000000>;
		qspi-quad-mode;

		#include "nrf70_common.dtsi"
		#include "nrf70_common_5g.dtsi"
	};
};

&spi3 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	pinctrl-0 = <&spi3_default>;
	pinctrl-1 = <&spi3_sleep>;
	pinctrl-names = "default", "sleep";

/* ---------------- Child device: Intan RHS2116 ---------------- */
	intanrhs: intanrhs@0 {
		compatible = "vnd,spi-device";
		status = "okay"; 
		reg = <0>; /* CS#0 */
		spi-max-frequency = <8000000>; 
		duplex = <0>; /* SPI_FULL_DUPLEX[2] */
		frame-format = <0>; /* Motorola */
		label = "IntanRHS";
	};
};


&dppic {
    compatible = "nordic,nrf-dppic";
    status = "okay";
};

&timer1 {
	status = "okay";
};


&gpiote1 {
	status = "okay";
};

  • #include <zephyr/logging/log.h>
    #include <haly/nrfy_gpio.h>
    #include <zephyr/net/socket.h>
    #include <zephyr/sys/fdtable.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>

    #include <zephyr/kernel.h>
    #include <hal/nrf_dppi.h>
    #include <nrfx_dppi.h>
    #include <nrfx_timer.h>
    #include <nrfx_spim.h>
    #include <nrfx_gpiote.h>

    #include "Wifi_Stationing.h"
    #include <unistd.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "UDP_Server_Ack.h"
    #include "deviceInformation.h"

    // White check mark FIX 1: Use a unique name for the log module
    LOG_MODULE_REGISTER(intan_spi, CONFIG_LOG_DEFAULT_LEVEL);

    #define SPI_RHD_STACK_SIZE 7000
    #define STM_PRIORITY 7

    static struct k_thread intanspi_rhd;
    K_THREAD_STACK_DEFINE(INTANSPI_RHD, SPI_RHD_STACK_SIZE);

    // --- Peripheral Configuration ---
    // TIMER
    #define TIMER_TOGGLE_INSTANCE 0
    #define TIMER_SPI_INSTANCE 1
    #define TIMER_FREQUENCY NRF_TIMER_FREQ_8MHz
    #define TIMER_PERIOD_MS 2
    #define CS_ACTIVE_US 10 // How long CS is held low (in microseconds)

    // Calculate timer ticks
    #define TICKS_PER_MICROSECOND 1
    #define PERIOD_TICKS (TIMER_PERIOD_MS * 10 * TICKS_PER_MICROSECOND)
    #define CS_ACTIVE_TICKS (CS_ACTIVE_US * TICKS_PER_MICROSECOND)

    #define DPPI_INSTANCE 0

    // SPIM
    #define SPI_INSTANCE 3
    #define SPI_SCK_PIN NRF_GPIO_PIN_MAP(1,13)
    #define SPI_MOSI_PIN NRF_GPIO_PIN_MAP(1,14)
    #define SPI_MISO_PIN NRF_GPIO_PIN_MAP(1,15)
    #define SPI_CS_PIN NRF_GPIO_PIN_MAP(1,12) // The pin we will control manually
    #define SPI_FREQUENCY NRFX_MHZ_TO_HZ(8)

    // Peripherals
    static const nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(TIMER_SPI_INSTANCE);
    static const nrfx_spim_t m_spim = NRFX_SPIM_INSTANCE(SPI_INSTANCE);
    static const nrfx_gpiote_t m_gpiote = NRFX_GPIOTE_INSTANCE(1);


    // DPPI Channels
    static uint8_t m_dppi_ch_timer_to_spi;
    static uint8_t m_dppi_ch_spi_to_cs_high;

    // Buffers and flags
    static uint8_t m_tx_buf[64] = {0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01,
    0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x01, 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01,
    0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x01,
    0x18, 0x01, 0x19, 0x01, 0x1a, 0x01, 0x1b, 0x01, 0x1c, 0x01, 0x1d, 0x01, 0x1e, 0x01, 0x1f, 0x01,};
    static uint8_t m_rx_buf[64];

    static volatile bool m_spi_xfer_done = false;

    // --- Event Handler ---
    void spim_event_handler(nrfx_spim_evt_t const *p_event, void *p_context)
    {
    if (p_event->type == NRFX_SPIM_EVENT_DONE) {
    m_spi_xfer_done = true;
    }
    }

    // --- Peripheral Initialization ---
    static void gpiote_init(void)
    {
    nrfx_err_t err;

    // nrfx_gpiote_init() is deprecated, use nrfx_gpiote_init_check and nrfx_gpiote_init
    if (!nrfx_gpiote_init_check(&m_gpiote)) {
    err = nrfx_gpiote_init(&m_gpiote, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
    NRFX_ASSERT(err == NRFX_SUCCESS);
    }
    nrfx_gpiote_output_config_t output_config = {
    .drive = NRF_GPIO_PIN_H0H1,
    .input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
    .pull = NRF_GPIO_PIN_NOPULL,
    };
    // The task polarity is relative to the task execution, not the pin level.
    // OUT task will set the pin to the state configured in .initial_value
    // CLR task will set it to the opposite. SET task will set it to the same.
    nrfx_gpiote_task_config_t task_config = {
    .task_ch = 0, // A specific channel can be used if needed, 0 is fine for basic tasks
    .polarity = GPIOTE_CONFIG_POLARITY_Toggle, // Not critical for OUT tasks, but good to define
    .init_val = NRF_GPIOTE_INITIAL_VALUE_HIGH
    };

    err = nrfx_gpiote_output_configure(&m_gpiote, SPI_CS_PIN, &output_config, &task_config);
    NRFX_ASSERT(err == NRFX_SUCCESS);
    }

    static void timer_init(void)
    {
    nrfx_err_t err;

    nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(TIMER_FREQUENCY);
    timer_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err = nrfx_timer_init(&m_timer, &timer_config, NULL); // No timer handler needed
    NRFX_ASSERT(err == NRFX_SUCCESS);

    nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, PERIOD_TICKS, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    nrfx_timer_compare(&m_timer, NRF_TIMER_CC_CHANNEL1, CS_ACTIVE_TICKS, false);

    LOG_INF("TIMER initialized. Period: %d ms, CS Active: %d us", TIMER_PERIOD_MS, CS_ACTIVE_US);
    }


    static void spim_init(void)
    {
    nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG(
    SPI_SCK_PIN,
    SPI_MOSI_PIN,
    SPI_MISO_PIN,
    NRF_SPIM_PIN_NOT_CONNECTED
    );
    spim_config.frequency = SPI_FREQUENCY;
    // White check mark FIX 4: Use the 'err' variable to make the code more robust.
    nrfx_err_t err = nrfx_spim_init(&m_spim, &spim_config, spim_event_handler, NULL);
    NRFX_ASSERT(err == NRFX_SUCCESS);
    LOG_INF("SPIM%d initialized with manual CS.", SPI_INSTANCE);
    }

    static void dppi_init_and_connect(void)
    {
    nrfx_err_t err;
    const nrfx_dppi_t m_dppi = NRFX_DPPI_INSTANCE(DPPI_INSTANCE);

    // DPPI 채널 할당
    err = nrfx_dppi_channel_alloc(&m_dppi, &m_dppi_ch_timer_to_spi);
    NRFX_ASSERT(err == NRFX_SUCCESS);
    err = nrfx_dppi_channel_alloc(&m_dppi, &m_dppi_ch_spi_to_cs_high);
    NRFX_ASSERT(err == NRFX_SUCCESS);

    uint32_t timer_compare0_evt = nrfx_timer_event_address_get(&m_timer, NRF_TIMER_EVENT_COMPARE0);
    uint32_t spim_start_task = nrfx_spim_start_task_address_get(&m_spim);
    uint32_t spim_end_evt = nrfx_spim_end_event_address_get(&m_spim);

    uint32_t timer_compare1_evt = nrfx_timer_event_address_get(&m_timer, NRF_TIMER_EVENT_COMPARE1);
    uint32_t gpiote_cs_set_task = nrfx_gpiote_set_task_address_get(&m_gpiote, SPI_CS_PIN);
    uint32_t gpiote_cs_clr_task = nrfx_gpiote_clr_task_address_get(&m_gpiote, SPI_CS_PIN);
    uint32_t gpiote_cs_out_task = nrfx_gpiote_out_task_address_get(&m_gpiote, SPI_CS_PIN);

    NRF_DPPI_ENDPOINT_SETUP(spim_start_task, m_dppi_ch_timer_to_spi);
    NRF_DPPI_ENDPOINT_SETUP(gpiote_cs_out_task, m_dppi_ch_timer_to_spi); // CS LOW
    NRF_DPPI_ENDPOINT_SETUP(timer_compare0_evt, m_dppi_ch_timer_to_spi);
    nrfx_dppi_channel_enable(&m_dppi, m_dppi_ch_timer_to_spi);

    NRF_DPPI_ENDPOINT_SETUP(spim_end_evt , m_dppi_ch_spi_to_cs_high);
    NRF_DPPI_ENDPOINT_SETUP(gpiote_cs_out_task, m_dppi_ch_spi_to_cs_high); // CS HIGH
    nrfx_dppi_channel_enable(&m_dppi, m_dppi_ch_spi_to_cs_high);

    LOG_INF("DPPI configured with corrected logic.");
    }

    // --- Main Thread ---
    int spi_rhd(void)
    {
    LOG_INF("Starting Periodic SPI with robust state management...");

    gpiote_init();
    spim_init();
    timer_init();
    dppi_init_and_connect();

    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_rx_buf));
    nrfx_spim_xfer(&m_spim, &xfer_desc, NRFX_SPIM_FLAG_HOLD_XFER);

    nrfx_timer_enable(&m_timer);

    while (1) {
    while (!m_spi_xfer_done) {
    k_sleep(K_MSEC(0.1));
    }
    m_spi_xfer_done = false;

    nrfx_spim_xfer(&m_spim, &xfer_desc, NRFX_SPIM_FLAG_HOLD_XFER);
    }
    return 0;
    }

    void Intan_SPI_Init(void) {
    k_thread_create(
    &intanspi_rhd,
    INTANSPI_RHD,
    SPI_RHD_STACK_SIZE,
    (k_thread_entry_t)spi_rhd,
    NULL,
    NULL,
    NULL,
    STM_PRIORITY,
    0,
    K_NO_WAIT
    );

    k_thread_name_set(&intanspi_rhd, "rhd_spi");
    k_thread_start(&intanspi_rhd);
    }
Related