RT1189 get wrong data when transfer from LPSPI_CPU to LPSPI_DMA Background MCU: MIMXRT1189 core: M33 only RTOS: Zephyr v4.3 I use MIMXRT1189 as SPI master and ADS1235 as SPI slave to collect ADC data. The related DTS content is here: &lpspi4 {
status = "okay";
cs-gpios = <&gpio5 17 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
dmas = <&edma4 18 15>, <&edma4 19 14>;
dma-names = "rx", "tx";
pinctrl-0 = <&pinmux_lpspi4>;
pinctrl-names = "default";
};
pinmux_lpspi4: pinmux_lpspi4 {
group0 {
pinmux = <&iomuxc_gpio_sd_b2_07_gpio5_io17>;
drive-strength = "high";
bias-pull-up;
slew-rate = "fast";
};
group1 {
pinmux = <&iomuxc_gpio_sd_b2_08_lpspi4_sck>,
<&iomuxc_gpio_sd_b2_10_lpspi4_sout>,
<&iomuxc_gpio_sd_b2_11_lpspi4_sin>;
drive-strength = "high";
slew-rate = "fast";
};
}; Previously, I disabled CONFIG_SPI_NXP_LPSPI_DMA and it worked well. Issue description Now I need to use DMA for LPSPI and make the buffer aligned to non-cacheable DTCM by doing something like static uint8_t spi_tx[9] __aligned(32) __dtcm_noinit_section;
static uint8_t spi_rx[9] __aligned(32) __dtcm_noinit_section; As stated in ADS1235 datasheet, the first byte of RX should be 0xFF and the second byte should echo the first byte of TX. I need to write multiple registers. If I write the registers one by one (call spi_transceive_dt for each write), I get data mismatched from the second register: [00:00:05.536,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x42 rx0=0xFF rx1=0xC2
[00:00:05.536,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x43 rx0=0x0F rx1=0xF3
[00:00:05.537,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x44 rx0=0xFF rx1=0xE4
[00:00:05.537,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x45 rx0=0x1F rx1=0xF5
[00:00:05.537,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x46 rx0=0xFF rx1=0xC6
[00:00:05.538,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x47 rx0=0x0F rx1=0xF7
[00:00:05.538,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x48 rx0=0xFF rx1=0xC8
[00:00:05.538,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x49 rx0=0xFF rx1=0xE9
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4A rx0=0xFF rx1=0xEA
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4B rx0=0x1F rx1=0xFB
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4C rx0=0xFF rx1=0xFC
[00:00:05.540,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4D rx0=0xFF rx1=0xFD
[00:00:05.540,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4E rx0=0x1F rx1=0xFE
[00:00:05.540,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4F rx0=0x3F rx1=0xEF
[00:00:05.540,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x50 rx0=0xFF rx1=0xF0
[00:00:05.541,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x51 rx0=0x1F rx1=0xF1 If I do spi_transceive_dt once for all registers, I get data mismatched in a different behavior: [00:00:05.538,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x47 rx0=0x0A rx1=0x3B
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x49 rx0=0x00 rx1=0xDB
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4B rx0=0x00 rx1=0xF1
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4D rx0=0x40 rx1=0x48
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x4F rx0=0x00 rx1=0xA5
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x51 rx0=0x07 rx1=0x31 Could anyone help me with this issue? i.MXRT Re: RT1189 get wrong data when transfer from LPSPI_CPU to LPSPI_DMA Hello Kan, These 2 captures show the first successful write and then followed by the second failed write. The 2nd MOSI is expected to 0x42 0x4B and MISO is expected to 0xFF 0x42. And from the second write it seems that both TX and RX are corrupted. The full successful (with LPSPI CPU) and failed (with LPSPI DMA) captures are attached to this reply. The SPI rate is 800KHz and the mode is CPOL = 0 and CPHA = 1. Re: RT1189 get wrong data when transfer from LPSPI_CPU to LPSPI_DMA Hi @renrad ,
Thanks for the reaching out! Is it possible to provide a four-channel capture of CS, SCK, MOSI, and MISO for one successful write followed by the first failing write , with the SPI clock rate and mode. That will show whether the unexpected bytes are on the wire or appear only in spi_rx
Thanks for your patience!
Have a great day, Kan
------------------------------------------------------------------------------- Note: - If this post answers your question, please click the "Mark Correct" button. Thank you! - We are following threads for 7 weeks after the last post, later replies are ignored Please open a new thread and refer to the closed one, if you have a related question at a later point in time. ------------------------------------------------------------------------------- Re: RT1189 get wrong data when transfer from LPSPI_CPU to LPSPI_DMA Hi @renrad ,
Thank you for the captures. In the second write, the bytes on MOSI appear to differ from the intended 0x42 0x4B . MISO appears to echo the command byte seen on the wire. This suggests we should first determine why the transmitted bytes differ, before treating the ADC response as a separate issue.
Could you please provide the code for the first two spi_transceive_dt() calls, including how the TX buffer is filled, the spi_buf pointers and lengths, and the return value of each call? Please also log the TX and RX buffer addresses and contents immediately before and after each call, and confirm where those buffers are placed in the linker map.
Finally, please confirm whether the second capture corresponds to the logged tx0=0x42, rx1=0xC2 mismatch. The apparent echo in the capture differs from that log value, so matching the capture to the exact transaction will help us distinguish a wire-level issue from an RX-buffer issue.
Have a great day, Kan
------------------------------------------------------------------------------- Note: - If this post answers your question, please click the "Mark Correct" button. Thank you! - We are following threads for 7 weeks after the last post, later replies are ignored Please open a new thread and refer to the closed one, if you have a related question at a later point in time. ------------------------------------------------------------------------------- Re: RT1189 get wrong data when transfer from LPSPI_CPU to LPSPI_DMA Hello Kan, The related code is here static uint8_t s_ads1235_spi_tx[32] __aligned(32) __dtcm_noinit_section;
static uint8_t s_ads1235_spi_rx[32] __aligned(32) __dtcm_noinit_section;
static void ads1235_spi_tranceive(uint8_t *data_tx, uint8_t *data_rx, uint8_t byte_length) {
struct spi_buf tx_bufs = { .buf = s_ads1235_spi_tx, .len = byte_length };
struct spi_buf rx_bufs = { .buf = s_ads1235_spi_rx, .len = byte_length };
struct spi_buf_set tx = { .buffers = &tx_bufs, .count = 1 };
struct spi_buf_set rx = { .buffers = &rx_bufs, .count = 1 };
int ret;
memcpy(s_ads1235_spi_tx, data_tx, byte_length);
memset(s_ads1235_spi_rx, 0, byte_length);
ret = spi_transceive_dt(&s_spi, &tx, &rx);
if (ret < 0) {
memset(data_rx, 0, byte_length);
LOG_ERR("ADS1235 SPI transfer failed: %d", ret);
} else {
memcpy(data_rx, s_ads1235_spi_rx, byte_length);
}
}
static bool ads1235_write_single_register(uint8_t addr, uint8_t data) {
// Check that the register address is in range
assert(addr < NUM_REGISTERS);
uint8_t data_tx[4];
uint8_t data_rx[4] = {0};
uint8_t byte_length = (CRC_BYTE_ENABLED ? 4 : 2);
// Build TX array and send it
data_tx[0] = OPCODE_WREG + (addr & 0x1F);
data_tx[1] = data;
// Currently CRC is not enabled
if (CRC_BYTE_ENABLED) {
data_tx[2] = ads1235_calc_crc8_by_table(data_tx, 2); // Compute CRC-2
data_tx[3] = s_adc_dont_care;
}
ads1235_spi_tranceive(data_tx, data_rx, byte_length);
// Handle SPI errors
// if (ads1235_validate_spi(data_tx, data_rx, OPCODE_WREG)) {
// LOG_ERR("ADS1235 write reg 0x%02X err", addr);
// return false;
//}
// update the global register map variable
s_ads1235_register_map[addr] = data;
return true;
}
static bool ads1235_write_multiple_registers(uint8_t addr, uint8_t count, const uint8_t data[]) {
for (uint8_t i = 0; i < count; i++) {
if (!ads1235_write_single_register(addr + i, data[i])) {
return false;
}
}
return true;
} The first byte of TX means opcode + address. The write opcode is 0x40. Thus, 0x41 means write address 0x01. After adding logging before/after spi_tranceive_dt, part of the log is shown below: [00:00:05.436,000] main: Initializing ADC
Before transfering TX: 0X41 0X 2
Before transfering RX: 0X 0 0X 0
After transfering TX: 0X41 0X 2
After transfering RX: 0XFF 0X41
Before transfering TX: 0X42 0X4B
Before transfering RX: 0X 0 0X 0
After transfering TX: 0X42 0X4B
After transfering RX: 0X 7 0XFE
[00:00:05.538,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x42 rx0=0x07 rx1=0xFE
Before transfering TX: 0X43 0X 1
Before transfering RX: 0X 0 0X 0
After transfering TX: 0X43 0X 1
After transfering RX: 0X F 0XFB
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x43 rx0=0x0F rx1=0xFB
Before transfering TX: 0X44 0XF0
Before transfering RX: 0X 0 0X 0
After transfering TX: 0X44 0XF0
After transfering RX: 0X F 0XF4
[00:00:05.539,000] ads1235: ADS1235 SPI validate mismatch: opcode=0x40 tx0=0x44 rx0=0x0F rx1=0xF4
--- 2 messages dropped ---
Before transfering TX: 0X45 0X60
Before transfering RX: 0X 0 0X 0
After transfering TX: 0X45 0X60
After transfering RX: 0X1F 0XF5 I can be sure that the second capture corresponds to the logged tx0=0x42, rx1=0xC2 mismatch. The problem I think is that the internal buffer for the driver is dirtied. Are the information I provided is enough and valuable?
View full article