about nrf54L15 chip SPI Port on sdk3.2.1.

I used  nrf54L15 chip P2 port's SPI.used  spi_transceive_dt tx 10 bytes. but chip divide two process (8Bytes+2Bytes).this result is not my object. code as below:

int spi00_dma_transceive(const uint8_t *tx, uint8_t *rx, size_t len)
{
    struct spi_buf tx_buf = {
        .buf = (void *)tx,
        .len = len,
    };
    struct spi_buf rx_buf = {
        .buf = rx,
        .len = len,
    };
    struct spi_buf_set tx_set = {
        .buffers = &tx_buf,
        .count   = 1,
    };
    struct spi_buf_set rx_set = {
        .buffers = &rx_buf,
        .count   = 1,
    };
    return spi_transceive_dt(&spi00_dev, &tx_set, &rx_set);
}
  • and CS is not right. this pin I not used other function. this is overlay file and SPI code.

    /*此文件非特殊需要尽量不要改动。雷正生 2026-01-20*/

    #include <zephyr/dt-bindings/input/input-event-codes.h>
    #include <zephyr/dt-bindings/comparator/nrf-comp.h>

    /*1、串口要用于和模块通信,删除和串口相关的任何关联 */
    / {
        chosen {
            /delete-property/ zephyr,console;
            /delete-property/ zephyr,shell-uart;
            /delete-property/ zephyr,uart-mcumgr;
            /delete-property/ zephyr,bt-mon-uart;
            /delete-property/ zephyr,bt-c2h-uart;
        };
    };

    /* 2、外部中断触发*/
    /{
        /*  2.1  输入低脉冲触发:下降沿触发*/
        gpio_inputs: gpio_inputs {
            compatible = "gpio-keys";
            int_fall_0: int_fall_0 { /* P0.01 PACE_IN2:起搏钉信号经过窗口比较器,输出低电平脉冲触发中断,下降沿触发 */
                gpios = <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "PACE_IN2";
                zephyr,code = <INPUT_KEY_0>;
            };
            int_fall_1: int_fall_1 { /* P1.13 ECG_RDY: 心电部分ADC数据采样准备就绪,输入低脉冲,下降沿触发,启动SPI读取 */
                gpios = <&gpio1 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "ECG_RDY";
                zephyr,code = <INPUT_KEY_1>;
            };
            int_fall_2: int_fall_2 { /* P1.14 BATDET_LOW: 电量检测IC低电量报警,输入低脉冲 */
                gpios = <&gpio1 14 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "BATDET_LOW";
                zephyr,code = <INPUT_KEY_2>;
            };
        };
        /*2.2、输出高低电平或者脉冲*/
        gpio_outputs: gpio_outputs {
            compatible = "gpio-leds";
            gpio_out0: gpio_out0 {
                gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;  /*P0.04,RF_U/S,RF模块通信接口设置,输出:H=UART,L=SPI。 */
                label = "RF_US";
            };
            gpio_out1: gpio_out1 {
                gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; /*P2.06,ECG_EN,心电部分启用,输出高电平开启ECG模拟供电和ECG芯片使能端。 */
                label = "ECG_EN";
            };
            gpio_out2: gpio_out2 {
                gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;/*P2.07,BATDET_WAKE,电量检测IC低功耗唤醒,输出高脉冲。 */
                label = "BATDET_WAKE";
            };
            gpio_out3: gpio_out3 {
                gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;/*P2.08,FSV_ON,快速电磁阀启动,输出高电平进行正常测量血压。 */
                label = "FSV_ON";
            };
            gpio_out4: gpio_out4 {
                gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;/*P2.09,POW_EN,系统电源开启,持续输出高电平。 */
                label = "POW_EN";
            };

            gpio_out5: gpio_out5 {
                gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;/*P*/
                label = "SPI20_CSN";
            };
        };
    };

    /*3、定义按键服务:  P0.0,KEY_ON,电源开关检测,开/关机时按下:按下去低电平,松开为高电平。特别注意:需要先删除原有的button节点和相关属性*/
    / {
        // /delete-node/ leds;
       
        aliases {
            /delete-property/ sw0;
            /delete-property/ sw1;
            /delete-property/ sw2;
            /delete-property/ sw3;
        };
        /delete-node/ buttons;
       

        buttons: buttons {
            status = "okay";
            compatible = "gpio-keys";
            debounce-interval-ms = <50>;
            button0: button_0 {
                gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "KEY_ON";
                zephyr,code = <INPUT_KEY_0>;
            };
        };
        btn_longpress: btn_longpress {
            input = <&buttons>;
            compatible = "zephyr,input-longpress";
            input-codes = <INPUT_KEY_0>;
            short-codes = <INPUT_KEY_1>;
            long-codes  = <INPUT_KEY_2>;
            long-delay-ms = <5000>;
            status = "okay";
        };
    };

    /*4、ADC 使用芯片内部参考0.9V */
    / {
        /* 1、定义三路ADC 采样通道*/
        zephyr,user {    
        io-channels = <&adc 0>, <&adc 1>, <&adc 2>; /* 三路 ADC 通道:0、1、2*/
        };
    };

    &adc {
        #address-cells = <1>;
        #size-cells = <0>;
        status = "okay";
        channel@0 {
            reg = <0>;
            zephyr,gain = "ADC_GAIN_1_4";
            zephyr,reference = "ADC_REF_INTERNAL";
            zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
            zephyr,input-positive = <NRF_SAADC_AIN2>;
            zephyr,resolution = <14>;
        };
        channel@1 {
            reg = <1>;
            zephyr,gain = "ADC_GAIN_1_4";
            zephyr,reference = "ADC_REF_INTERNAL";
            zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
            zephyr,input-positive = <NRF_SAADC_AIN4>;
            zephyr,resolution = <14>;
        };
        channel@2 {
            reg = <2>;
            zephyr,gain = "ADC_GAIN_1_4";
            zephyr,reference = "ADC_REF_INTERNAL";
            zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
            zephyr,input-positive = <NRF_SAADC_AIN5>;
            zephyr,resolution = <14>;
        };
    };

    /* 5、定义通信口 */
    &i2c30 {
        status = "okay";
        pinctrl-0 = <&i2c30_default>;
        pinctrl-1 = <&i2c30_sleep>;
        pinctrl-names = "default", "sleep";
        clock-frequency = <I2C_BITRATE_FAST>; /* 400kHz */
        rd_i2c_uc6330@98 {
            compatible = "i2c-device";
            reg = <0x98>; //地址根据芯片更改
            label = "UC6330";
        };
        rd_bq27427@55 {
            compatible = "i2c-device";
            reg = <0x55>; //地址根据芯片更改
            label = "BQ27427";
        };
    };

    &uart21 {
        compatible = "nordic,nrf-uarte";
        status = "okay";
        current-speed = <921600>;
        pinctrl-0 = <&uart21_default>;
        pinctrl-1 = <&uart21_sleep>;
        pinctrl-names = "default", "sleep";
    };

    &uart22 {
        compatible = "nordic,nrf-uarte";
        status = "okay";
        current-speed = <115200>;
        pinctrl-0 = <&uart22_default>;
        pinctrl-1 = <&uart22_sleep>;
        pinctrl-names = "default", "sleep";
    };

    &spi00 {
        compatible = "nordic,nrf-spim";
        status = "okay";
        pinctrl-0 = <&spi00_default>;
        pinctrl-1 = <&spi00_sleep>;
        pinctrl-names = "default", "sleep";
        // cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
        rd_spi_00: rd_spi_00@0 {
            compatible = "rd-spi-device"; //compatible = "spi-device vnd,spi-device";
            reg = <0>;
            duplex = <0>;
            frame-format = <0>;
            spi-max-frequency = <8000000>;
            spi-cpha;
            //spi-cpol;
            label = "rd_spi_00";
        };
    };

    &spi20 {
        compatible = "nordic,nrf-spim";
        status = "okay";
        pinctrl-0 = <&spi20_default>;
        pinctrl-1 = <&spi20_sleep>;
        pinctrl-names = "default", "sleep";
        // cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
        rd_spi_20: rd_spi_20@0 {
            compatible = "rd-spi-device"; //compatible = "spi-device vnd,spi-device";;
            reg = <0>;
            duplex = <0>;
            frame-format = <0>;
            spi-max-frequency = <8000000>;
            spi-cpha;
            //spi-cpol;
            label = "rd_spi_20";
        };
    };
    /*6、定义比较器 */
    &comp {
        status = "okay";
        main-mode = "SE";
        psel = <NRF_COMP_AIN1>;
        refsel = "VDD";
        sp-mode = "NORMAL";
        th-up = <32>;
        th-down = <30>;
        isource = "DISABLED";
    };

    /*7、开启定时器 */
    &timer20 { status = "okay"; };
    &timer21 { status = "okay"; };
    &gpio0 { status = "okay"; };
    &gpio1 { status = "okay"; };
    &gpio2 { status = "okay"; };

    /*8、关闭默认的驱动,避免编译竞争 */
    &uart00 { status = "disabled"; };
    &uart20 { status = "disabled"; };
    &uart30 { status = "disabled"; };
    &spi21  { status = "disabled"; };
    &spi22  { status = "disabled"; };
    &i2c20  { status = "disabled"; };
    &i2c21  { status = "disabled"; };
    &i2c22  { status = "disabled"; };
    &lfxo   { status = "disabled"; };
    &uicr   { nfct-pins-as-gpios;  };

    /*9、通信口管脚定义 */
    &pinctrl {
        i2c30_default: i2c30_default {
            group1 {
                psels = <NRF_PSEL(TWIM_SCL, 0, 3)>,
                        <NRF_PSEL(TWIM_SDA, 0, 2)>;
                nordic,drive-mode = <NRF_DRIVE_H0S1>;
                bias-pull-up;
            };
        };
        i2c30_sleep: i2c30_sleep {
            group1 {
                psels = <NRF_PSEL(TWIM_SCL, 0, 3)>,
                        <NRF_PSEL(TWIM_SDA, 0, 2)>;
                low-power-enable;
            };
        };

        uart21_default: uart21_default {
            group1 {
                psels = <NRF_PSEL(UART_TX, 1, 9)>;
                nordic,drive-mode = <NRF_DRIVE_H0H1>;
            };
            group2 {
                psels = <NRF_PSEL(UART_RX, 1, 10)>;
                bias-pull-up;
            };
        };
        uart21_sleep: uart21_sleep {
            group1 {
                psels = <NRF_PSEL(UART_TX, 1, 9)>,
                        <NRF_PSEL(UART_RX, 1, 10)>;
                low-power-enable;
            };
        };

        uart22_default: uart22_default {
            group1 {
                psels = <NRF_PSEL(UART_TX, 1, 1)>;
                nordic,drive-mode = <NRF_DRIVE_H0H1>;
            };
            group2 {
                psels = <NRF_PSEL(UART_RX, 1, 2)>;
                bias-pull-up;
            };
        };
        uart22_sleep: uart22_sleep {
            group1 {
                psels = <NRF_PSEL(UART_TX, 1, 1)>,
                        <NRF_PSEL(UART_RX, 1, 2)>;
                low-power-enable;
            };
        };

        spi00_default: spi00_default {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 2, 1)>,
                        <NRF_PSEL(SPIM_MOSI, 2, 2)>,//输出 SDO
                        <NRF_PSEL(SPIM_MISO, 2, 4)>,//输入 SDI
                        <NRF_PSEL(SPIM_CSN, 2, 5)>;//输入 CS
                nordic,drive-mode = <NRF_DRIVE_E0E1>;
                bias-pull-up;
                //bias-disable;
            };
        };
        spi00_sleep: spi00_sleep {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 2, 1)>,
                        <NRF_PSEL(SPIM_MOSI, 2, 2)>,//输出 SDO
                        <NRF_PSEL(SPIM_MISO, 2, 4)>,//输入 SDI
                        <NRF_PSEL(SPIM_CSN, 2, 5)>;//输入 CS
                //low-power-enable;
                bias-pull-up;
            };
        };

        spi20_default: spi20_default {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 1, 3)>,
                        <NRF_PSEL(SPIM_MOSI, 1, 4)>, //输出 SDO
                        <NRF_PSEL(SPIM_MISO, 1, 7)>; //输入 SDI
                        //<NRF_PSEL(SPIM_CSN, 1, 8)>; //CS
                nordic,drive-mode = <NRF_DRIVE_H0H1>;
                bias-pull-up;
                //bias-disable;
            };
        };
        spi20_sleep: spi20_sleep {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 1, 3)>,
                        <NRF_PSEL(SPIM_MOSI, 1, 4)>,//输出 SDO
                        <NRF_PSEL(SPIM_MISO, 1, 7)>;//输入 SDI
                        //<NRF_PSEL(SPIM_CSN, 1, 8)>; //CS
                // low-power-enable;
                bias-pull-up;
            };
        };
    };
    /delete-node/ &mx25r64;
     
    #include <nrfx_spim.h>
    #include <hal/nrf_gpio.h>

    #include "HW_SPI.h"


    #define SPI_OP_FLAGS (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPHA)

    /* 从子节点 RD_SPI_00 / RD_SPI_20 生成 spi_dt_spec */
    static const struct spi_dt_spec spi00_dev = SPI_DT_SPEC_GET(DT_NODELABEL(rd_spi_00), SPI_OP_FLAGS, 0);
    static const struct spi_dt_spec spi20_dev = SPI_DT_SPEC_GET(DT_NODELABEL(rd_spi_20), SPI_OP_FLAGS, 0);

    void spi00_config_csn(void)
    {
        // 假设 NRF_SPIM00 是你在 DTS 里用的 spi00 实例
        // pin 参数要与 PSEL.CSN 一致;如果 DTS 驱动已经配置了 PSEL.CSN,
        // 这里可以只改 duration(或直接写 IFTIMING.CSNDUR)
        uint32_t csn_pin = NRF_GPIO_PIN_MAP(2, 5);/* P2.05 对应的 pin 编号,需查头文件 */;
        uint32_t duration = 5; // 先设大一点,方便示波器观察
        nrfy_spim_csn_configure(NRF_SPIM00,csn_pin,NRF_SPIM_CSN_POL_LOW,duration);
    }

    void spi20_config_csn(void)
    {
        // 假设 NRF_SPIM00 是你在 DTS 里用的 spi00 实例
        // pin 参数要与 PSEL.CSN 一致;如果 DTS 驱动已经配置了 PSEL.CSN,
        // 这里可以只改 duration(或直接写 IFTIMING.CSNDUR)
        uint32_t csn_pin = NRF_GPIO_PIN_MAP(1, 8);/* P1.08 对应的 pin 编号,需查头文件 */;
        uint32_t duration = 5; // 先设大一点,方便示波器观察
        nrfy_spim_csn_configure(NRF_SPIM20,csn_pin,NRF_SPIM_CSN_POL_LOW,duration);
    }

    /* 4. 初始化:检查设备和 CS 是否 ready */
    static int spi00_dma_init(void)
    {
        if (!spi_is_ready_dt(&spi00_dev)) {
            printk("spi00_dev init is error\r\n");
            return API_ERR_DEV_NOT_READY;
        }
        NRF_GPIOHSPADCTRL->BIAS = 0x03;
        spi00_config_csn();
        return RET_SUCCESS;
    }

    static int spi20_dma_init(void)
    {
        if (!spi_is_ready_dt(&spi20_dev)) {
            printk("spi20_dev init is error \r\n");
            return API_ERR_DEV_NOT_READY;
        }
        return RET_SUCCESS;
    }

    /* 5. 只写:spi_write() */
    static int spi00_dma_write(const uint8_t *tx, size_t len)
    {
        struct spi_buf tx_buf = {
            .buf = (void *)tx,
            .len = len,
        };
        struct spi_buf_set tx_set = {
            .buffers = &tx_buf,
            .count   = 1,
        };
        spi_write_dt(&spi00_dev, &tx_set);
        return RET_SUCCESS;
    }

    static int spi20_dma_write(bool pCSCtrlFlag,const uint8_t *tx, size_t len)
    {

        struct spi_buf tx_buf = {
            .buf = (void *)tx,
            .len = len,
        };
        struct spi_buf_set tx_set = {
            .buffers = &tx_buf,
            .count   = 1,
        };
        if (pCSCtrlFlag)
        {
            CHW_Gpio_Set_HL_Level(SPI20_CSN,0);
            spi_write_dt(&spi20_dev, &tx_set);
            CHW_Gpio_Set_HL_Level(SPI20_CSN,1);
        }
        else spi_write_dt(&spi20_dev, &tx_set);
        return RET_SUCCESS;
    }

    /* 6. 全双工收发:spi_transceive() */
    static int spi00_dma_transceive(const uint8_t *tx, uint8_t *rx, size_t len)
    {
        struct spi_buf tx_buf = {
            .buf = (void *)tx,
            .len = len,
        };
        struct spi_buf rx_buf = {
            .buf = rx,
            .len = len,
        };
        struct spi_buf_set tx_set = {
            .buffers = &tx_buf,
            .count   = 1,
        };
        struct spi_buf_set rx_set = {
            .buffers = &rx_buf,
            .count   = 1,
        };
        spi_transceive_dt(&spi00_dev, &tx_set, &rx_set);
        return RET_SUCCESS;
    }

    static int spi20_dma_transceive(bool pCSCtrlFlag,const uint8_t *tx, uint8_t *rx, size_t len)
    {
        struct spi_buf tx_buf = {
            .buf = (void *)tx,
            .len = len,
        };
        struct spi_buf rx_buf = {
            .buf = rx,
            .len = len,
        };
        struct spi_buf_set tx_set = {
            .buffers = &tx_buf,
            .count   = 1,
        };
        struct spi_buf_set rx_set = {
            .buffers = &rx_buf,
            .count   = 1,
        };
       
        if (pCSCtrlFlag)
        {
           CHW_Gpio_Set_HL_Level(SPI20_CSN,0);
           spi_transceive_dt(&spi20_dev, &tx_set, &rx_set);
           CHW_Gpio_Set_HL_Level(SPI20_CSN,1);
        }
        else spi_transceive_dt(&spi20_dev, &tx_set, &rx_set);
        return RET_SUCCESS;
    }

    /* 7. 只读:spi_read() */
    static int spi00_dma_read(uint8_t *rx_buf, size_t len)
    {
        struct spi_buf rx = {
            .buf = rx_buf,
            .len = len,
        };
        struct spi_buf_set rx_set = {
            .buffers = &rx,
            .count   = 1,
        };
        spi_read_dt(&spi00_dev, &rx_set);
        return RET_SUCCESS;
    }

    static int spi20_dma_read(bool pCSCtrlFlag,uint8_t *rx_buf, size_t len)
    {
        struct spi_buf rx = {
            .buf = rx_buf,
            .len = len,
        };
        struct spi_buf_set rx_set = {
            .buffers = &rx,
            .count   = 1,
        };
        if (pCSCtrlFlag)
        {
            CHW_Gpio_Set_HL_Level(SPI20_CSN,0);
            spi_read_dt(&spi20_dev, &rx_set);
            CHW_Gpio_Set_HL_Level(SPI20_CSN,1);
        }
        else spi_read_dt(&spi20_dev, &rx_set);
        return RET_SUCCESS;
    }

    /* 8. 对外封装接口(保持你原来的函数名) */
    int CHW_SPI_Init(void)
    {
        spi00_dma_init();
        spi20_dma_init();
        return RET_SUCCESS;
    }

    int CHW_SPI00_MCpu_DMA_Write(const uint8_t *tx, size_t len)
    {
        return spi00_dma_write(tx, len);
    }

    int CHW_SPI20_Heart_DMA_Write(bool pCSCtrlFlag,const uint8_t *tx, size_t len)
    {
        return spi20_dma_write(pCSCtrlFlag,tx, len);
    }

    int CHW_SPI00_MCpu_DMA_WriteRead(const uint8_t *tx, uint8_t *rx, size_t len)
    {
        return spi00_dma_transceive(tx, rx, len);
    }

    int CHW_SPI20_Heart_DMA_WriteRead(bool pCSCtrlFlag,const uint8_t *tx, uint8_t *rx, size_t len)
    {
        return spi20_dma_transceive(pCSCtrlFlag,tx, rx, len);
    }

    int CHW_SPI00_MCpu_DMA_Read(uint8_t *rx_buf, size_t len)
    {
        return spi00_dma_read(rx_buf, len);
    }

    int CHW_SPI20_Heart_DMA_Read(bool pCSCtrlFlag,uint8_t *rx_buf, size_t len)
    {
        return spi20_dma_read(pCSCtrlFlag,rx_buf, len);
    }
  • Hello,

    This is not a recommended way to configure CSN like combining zephyr driver APIs with direct nrfx/HAL/HALY calls.

    Can you please look at this dev academy course Exercise 1 - Interfacing with a sensor over SPI - Nordic Developer Academy

Related