BSACPLD 14 31 января, 2021 Опубликовано 31 января, 2021 · Жалоба Коллеги, помогите, пожалуйста, понять в чем проблема. Читаю данные из EEPROM 24XX64. При чтении последнего байта выдаю NACK. После этого STOP. Все читается как надо, только меня смущает наличие лишней транзакции чтения после чтения последнего байта (тоже с NACK). Вот код и скриншот из лог. анализатора. Работа с I2C: // control_i2c.c #include <stm32f10x.h> #include <stm32f10x_i2c.h> #include <stdint.h> #include <stdbool.h> #include "main.h" #include "system.h" #include "control_i2c.h" //--------------------------------------------------------------------------- void I2C_INIT (void) { // Настройка I2C I2C1->CR2 = (CPU_CLOCK_HZ / 2) / 1000000 ; I2C1->CCR = I2C_CCR_FS | I2C_CCR_DUTY | 4 ; I2C1->TRISE = 12 ; // Включение I2C I2C1->CR1 = I2C_CR1_PE ; } //--------------------------------------------------------------------------- void start_I2C (void) { I2C1->CR1 |= I2C_CR1_START ; while ((I2C1->SR1 & I2C_SR1_SB) == 0) ; } //--------------------------------------------------------------------------- void stop_I2C (void) { I2C1->CR1 |= I2C_CR1_STOP ; while ((I2C1->SR2 & I2C_SR2_BUSY) == 0) ; } //--------------------------------------------------------------------------- bool write_byte_I2C (uint8_t data) { I2C1->DR = data ; while (true) { uint16_t SR1 = I2C1->SR1 ; if (SR1 & I2C_SR1_AF) { I2C1->SR1 &= ~I2C_SR1_AF ; stop_I2C () ; return false ; } if (SR1 & I2C_SR1_ADDR) { (void) I2C1->SR2 ; break ; } if (SR1 & I2C_SR1_BTF) { break ; } } return true ; } //--------------------------------------------------------------------------- uint8_t read_byte_I2C (bool ack) { if (ack) I2C1->CR1 |= I2C_CR1_ACK ; else I2C1->CR1 &= ~I2C_CR1_ACK ; while ((I2C1->SR1 & I2C_SR1_RXNE) == 0) ; return I2C1->DR ; } //--------------------------------------------------------------------------- Работа с EEPROM: bool ReadFlashMM (uint8_t n_mm, uint16_t address, uint8_t* data, uint16_t size) { uint8_t chip_a = MM_FLASH_I2C_ADDR + (n_mm << 1) ; // S start_I2C () ; // AD+W if (!write_byte_I2C(chip_a)) return false ; // MA H if (!write_byte_I2C(HIBYTE(address))) return false ; // MA L if (!write_byte_I2C(LOBYTE(address))) return false ; // S start_I2C () ; // AD+R if (!write_byte_I2C(chip_a | 0x01)) return false ; for (uint16_t i=0 ; i<size ; i++) { // DATA if (i == (size-1)) data[i] = read_byte_I2C (false) ; else data[i] = read_byte_I2C (true) ; } // P stop_I2C () ; return true ; } Скриншот из лог. анализатора: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 31 января, 2021 Опубликовано 31 января, 2021 · Жалоба Код я даже не смотрел, так как причина вполне очевидна. В RM подробнейшим образом описан механизм транзакций чтения и записи. ST там, конечно, наворотили, поэтому работа с битами управления для байтов N (последнего), N-1, N-2-... - отличается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 9 февраля, 2021 Опубликовано 9 февраля, 2021 · Жалоба У вас много ошибок и неточностей в коде. Основные: 1) Мастер после подачи старт-условия должен дождаться появления флага SB, вдруг шина занята... 2) Мастер после передачи адреса слейва+0, должен дождаться появления флага ADDR=1. 3) Чтобы передать байт от мастера к слейву, надо дождаться флага TxE=1, и только потом передавать байт. 4) Чтобы принять байт от слейва, надо дождаться флага RxNE=1, и только после этого принять байт. 5) После каждого ивента надо чистить флаги. Учтите слейв передаёт столько байт, сколько требует мастер, не больше, не меньше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BSACPLD 14 13 февраля, 2021 Опубликовано 13 февраля, 2021 · Жалоба On 2/9/2021 at 11:50 PM, =GM= said: У вас много ошибок и неточностей в коде. Основные: 1) Мастер после подачи старт-условия должен дождаться появления флага SB, вдруг шина занята... 2) Мастер после передачи адреса слейва+0, должен дождаться появления флага ADDR=1. 3) Чтобы передать байт от мастера к слейву, надо дождаться флага TxE=1, и только потом передавать байт. 4) Чтобы принять байт от слейва, надо дождаться флага RxNE=1, и только после этого принять байт. 5) После каждого ивента надо чистить флаги. Учтите слейв передаёт столько байт, сколько требует мастер, не больше, не меньше. 1) А это разве не ожидание? while ((I2C1->SR1 & I2C_SR1_SB) == 0) ; 2) А это не проверка флага ADDR? while (true) { uint16_t SR1 = I2C1->SR1 ; if (SR1 & I2C_SR1_AF) { I2C1->SR1 &= ~I2C_SR1_AF ; stop_I2C () ; return false ; } if (SR1 & I2C_SR1_ADDR) { (void) I2C1->SR2 ; break ; } 3) Либо через флаг BTF. if (SR1 & I2C_SR1_BTF) { break ; } 4) А разве я делаю по другому? while ((I2C1->SR1 & I2C_SR1_RXNE) == 0) ; return I2C1->DR ; Вообще я уже нашел как обойти глюк с лишним байтом. Запись флага STOP в CR1 нужно делать ДО окончания приема последнего байта, а не после. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться