5

Objective: implement a single byte I²C slave on STM32.

Materials: STM32L452RE Nucleo-64 board, HAL Library, CH341 USB-I²C adapter(1), Artix Linux with Runit, Rhode & Schwarz RTB2004 oscilloscope

Question

How can I control the slave ACK signal?

As I will present, ACK is sometimes sent, sometimes not sent. My guess would be with I2C_FIRST_FRAME, I2C_NEXT_FRAME and I2C_LAST_FRAME - but they don't seem to have any effect!

Minimal example

The following non-functional example should:

  • receive cnt number and cnt bytes, storing them in a buffer;
  • transmit cnt number and cnt bytes;
  • keep updating UART output with current stored buffer.

7-bit slave address is 0x6E.

void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef* hi2c) {
    HAL_I2C_EnableListen_IT(hi2c);
}

void HAL_I2C_AddrCallback(I2C_HandleTypeDef* hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) {
    if (TransferDirection == I2C_DIRECTION_TRANSMIT) {
        HAL_I2C_Slave_Seq_Receive_DMA(hi2c, &cnt, 1, I2C_FIRST_FRAME);
        HAL_I2C_Slave_Seq_Receive_DMA(hi2c, buffer, cnt, I2C_LAST_FRAME);
    } else {
        HAL_I2C_Slave_Seq_Transmit_DMA(hi2c, &cnt, 1, I2C_FIRST_FRAME);
        HAL_I2C_Slave_Seq_Transmit_DMA(hi2c, buffer, cnt, I2C_LAST_FRAME);
    }
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef* hi2c) {
}

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef* hi2c) {
}

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c) {
}

void buffer_print(const uint8_t buf[], const char* name, const size_t size) {
    printf("%-20s[ ", name);
    for (uint8_t i = 0; i < size; ++i)
        printf("0x%04X ", i);
    printf("]\r\n                      ");
    for (uint8_t i = 0; i < size; ++i)
        printf("  0x%02X ", buf[i]);
    printf("\r\n");
}
#define BUFFER_PRINT(buffer, size) buffer_print(buffer, #buffer, size)

int main() {
    //...
    HAL_I2C_EnableListen_IT(&hi2c3);
    while (1) {
        BUFFER_PRINT(buffer, cnt);
        HAL_Delay(100);
    }
}

How am I testing: with the following shell script:

#!/bin/bash -e

bus=$(i2cdetect -l | awk '/ch341/ {gsub("i2c-","",$1); print $1}')
dev="6e"

echo "Bus is ${bus}"
[ ! -c "/dev/i2c-${bus}" ] && echo "Bus /dev/i2c-${bus} not found" && exit

i2cdetect -y ${bus}
if ! i2cdetect -y ${bus} | grep ${dev} >/dev/null; then
    echo "Device not found"
    exit
fi

dev="0x${dev}"
size=10

echo "Writing ${size} consecutive bytes"
i2ctransfer -y ${bus} w$(( size + 1 ))@${dev} ${size} 0x01+
echo "Reading bytes"
i2ctransfer -y ${bus} w1@${dev} ${size} r${size}

Testing write operation

  • No stretch
  • Analog filter does not have an effect

write operation

write operation

  • With HAL_I2C_Slave_Seq_Receive_DMA(), received buffer will show:
buffer [ 0x0000 ] <-- wrong cnt
           0x01   <-- correct value
  • With HAL_I2C_Slave_Seq_Receive_IT(), received buffer will show:
buffer [ 0x0000 0x0001 0x0002 0x0003 0x0004 0x0005 0x0006 0x0007 0x0008 0x0009 ] <-- correct cnt
           0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00   <-- wrong values

ACK is randomly not sent.

detail on write operation: ACK and NACK signs

detail on write operation: ACK and NACK signs

ACK looks like this:

detail on ACK sign

detail on ACK sign

NACK looks the same like ACK:

detail on NACK sign

detail on NACK sign

Sometimes, no ACK will be sent:

write operation without ACK

write operation without ACK

Independent of ACK and NACK, reported buffer will be the same.


Thank you!

(1): Used driver

tweak
  • 51
  • 3
  • Those spikes on the first picture are very strange (SDA). Do you have a picture of the setup and maybe a short schematic? – RemyHx Jul 24 '22 at 16:47
  • Sorry for the (really) late comment. When you asked this, I've already moved on, so unfortunately I cannot provide any photos. I was also wondering that and came to the conclusion, that the digital probe is misinterpreting something. I finished "solving" the problem, but I don't know how: I came back from something that worked and re-added my project to the minimal example.... Now it works, but I cant say how. – tweak Oct 26 '22 at 19:47
  • 2
    @tweak - Hi, If (as I understand your comment) your problem is solved, and you can't now provide any more info, then I recommend you delete your question (on a desktop web browser you should see a link marked "Delete" below the question, next to "Flag" - mobile browsers might not display it). That way, no-one else wastes time analysing a question that isn't going to go anywhere, potential solutions can't be tested etc. Thanks. – SamGibson Oct 26 '22 at 19:56

0 Answers0