Страница 1 из 2

[РЕШЕНО]stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 12:30:16
gruffi
Добрый день, форумчане.
Не получается стабильно читать из eeprom по i2c.

Код: Выделить всё

void I2C_EE_ReadBytes(uint8_t addr, uint8_t* data, uint8_t size)
{ 
    _data = data;
    bytes = 0;
    
    I2C1->CR2 &= ~(I2C_CR2_ADD10 | I2C_CR2_RD_WRN);
    I2C1->CR2 |= (1 << I2C_CR2_NBYTES_Pos) | addr | I2C_CR2_START;
    
    while((I2C1->ISR & I2C_ISR_TXIS) != I2C_ISR_TXIS);
    
    I2C1->TXDR = 0x00;
    
    while((I2C1->ISR & I2C_ISR_TC) != I2C_ISR_TC);
    
    I2C1->CR2 |= I2C_CR2_AUTOEND | (size << I2C_CR2_NBYTES_Pos) | I2C_CR2_RD_WRN
               | I2C_CR2_START | addr;

    for(bytes = 0; bytes < size; ++bytes)
    {
        while((I2C1->ISR & I2C_ISR_RXNE) != I2C_ISR_RXNE);
        _data[bytes] = I2C1->RXDR;
    }
}
Не выставляется флаг I2C_ISR_TXIS и программа зависает...
Если закомментировать кусок кода

Код: Выделить всё

I2C1->CR2 &= ~(I2C_CR2_ADD10 | I2C_CR2_RD_WRN);
I2C1->CR2 |= (1 << I2C_CR2_NBYTES_Pos) | addr | I2C_CR2_START;
    
while((I2C1->ISR & I2C_ISR_TXIS) != I2C_ISR_TXIS);
    
I2C1->TXDR = 0x00;
    
while((I2C1->ISR & I2C_ISR_TC) != I2C_ISR_TC);
то тогда все читается, но так нельзя выставить позицию с которой надо читать.
Где может быть затык?
Спасибо.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 12:35:10
uldemir
В своих конструкциях я использовал код сделанный на основе этого: http://cxem.net/mc/mc362.php

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 13:02:26
gruffi
Спасибо.
Сделал, как написано, но все равно прочитать не могу - один плюс, что не зависает. Проходит только START и получение на него ACK, и больше ничего. Есть еще предположения где у меня траблы?

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 13:12:25
uldemir
А что за eeprom? с 24c32 надо выдавать 16-ти битный адрес.

Код: Выделить всё

#define EEPROM_ADDR        0xA0
#ifdef EE24C32    
    if (i2c_rd_reg16(EEPROM_ADDR, EEREG_ADDR, pData, sizeof(data)) == I2C_SUCCESS) {
#else
    if (i2c_rd_reg(EEPROM_ADDR, EEREG_ADDR, pData, sizeof(data)) == I2C_SUCCESS) {
#endif  
СпойлерСейчас все нюансы уже не помню, но вот этот код у меня сейчас как раз трудится в чтении ЕЕПРОМ

Код: Выделить всё

t_i2c_status i2c_rd_reg16(unsigned char address, uint16_t reg_addr, char * data, unsigned char length){

    unsigned char Count = 0, reg_hi_lo[2], *reg_ptr;
    
    reg_hi_lo[0] = reg_addr>>8;
    reg_hi_lo[1] = reg_addr & 0xFF;
    reg_ptr = reg_hi_lo;
    
    I2C_BUS->CR2 = I2C_CR2_START | 2<<16 | (address & 0xFE); /* Go */
    while ((I2C_BUS->ISR & I2C_ISR_BUSY) == 0);    // Ожидать выдачу старта
    // Сейчас либо I2C запросит первый байт для отправки,
    // Либо взлетит NACK-флаг, говорящий о том, что микросхема не отвечает.
    // Если взлетит NACK-флаг, отправку прекращаем.

    while ((((I2C_BUS->ISR & I2C_ISR_TC)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY)) {
        if (I2C_BUS->ISR & I2C_ISR_TXIS) I2C_BUS->TXDR = *reg_ptr++;    // Отправляю адрес регистра
    }
    
    
    I2C_BUS->CR2 = I2C_CR2_START | ((uint32_t)length<<16) | I2C_CR2_RD_WRN | (address & 0xFE); /* Restart */
    while ((I2C_BUS->ISR & I2C_ISR_BUSY)==0);    // Ожидать выдачу старта

    // Принимаем байты до тех пор, пока не взлетит TC-флаг.
    // Если взлетит NACK-флаг, приём прекращаем.
    while ((((I2C_BUS->ISR & I2C_ISR_TC)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY))    {
        if (I2C_BUS->ISR & I2C_ISR_RXNE) {
            *data++ = I2C_BUS->RXDR;    // Принимаю данные
            Count++;
        }
    }

    I2C_BUS->CR2 |= I2C_CR2_STOP;                // Выдать стоп на шину
    while (I2C_BUS->ISR & I2C_ISR_BUSY);        // Ожидать выдачу стопа
    // Очищаю флаги - необходимо для дальнейшей работы шины
    I2C_BUS->ICR |= I2C_ICR_STOPCF;        // STOP флаг
    I2C_BUS->ICR |= I2C_ICR_NACKCF;        // NACK флаг
    // Если есть ошибки на шине - очищаю флаги
    if (I2C_BUS->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR)) {
        I2C_BUS->ICR |= I2C_ICR_ARLOCF;
        I2C_BUS->ICR |= I2C_ICR_BERRCF;
    }

  if (Count == length) return I2C_SUCCESS;
    else return I2C_ERROR;
} 

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 13:20:30
gruffi
Память AT24C08D 8Kbit...В даташит написано, что надо выдавать 8-битный адрес после СТАРТ:
Accessing the device requires an 8-bit Device Address word following a Start condition to enable the device for
a Read or Write operation. Since multiple slave devices can reside on the serial bus, each slave device must
have its own unique address so the Master can access each device indepen dently.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 13:37:40
uldemir
Эта... а вам компилятор варнинги не выдаёт?
например на это: size << I2C_CR2_NBYTES_Pos. Справа у вас должно быть 16, а size описана как 8-бит. получается 0. Хотя если int у вашего компилятора 32 бита, то проблемы быть не должно...

Ладно, вот еще мой код для 8-битной адресации (но не проверенный. Не было у меня такой маленькой еепромки):
Спойлер

Код: Выделить всё

//******************************************************************************
// Чтение регистра slave-устройства
// Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop 
//******************************************************************************                                   
t_i2c_status i2c_rd_reg(unsigned char address, unsigned char reg_addr, char * data, unsigned char length){

    unsigned char Count = 0;
        
    I2C_BUS->CR2 = I2C_CR2_START | 1<<16 | (address & 0xFE); /* Go */
    while ((I2C_BUS->ISR & I2C_ISR_BUSY) == 0);    // Ожидать выдачу старта
    // Сейчас либо I2C запросит первый байт для отправки,
    // Либо взлетит NACK-флаг, говорящий о том, что микросхема не отвечает.
    // Если взлетит NACK-флаг, отправку прекращаем.
    while ((((I2C_BUS->ISR & I2C_ISR_TC)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY))    {
        if (I2C_BUS->ISR & I2C_ISR_TXIS) I2C_BUS->TXDR = reg_addr;    // Отправляю адрес регистра
    }
    
    I2C_BUS->CR2 = I2C_CR2_START | ((uint32_t)length<<16) | I2C_CR2_RD_WRN | (address & 0xFE); /* Restart */
    while ((I2C_BUS->ISR & I2C_ISR_BUSY)==0);    // Ожидать выдачу старта

    // Принимаем байты до тех пор, пока не взлетит TC-флаг.
    // Если взлетит NACK-флаг, приём прекращаем.
    while ((((I2C_BUS->ISR & I2C_ISR_TC)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY))    {
        if (I2C_BUS->ISR & I2C_ISR_RXNE) {
            *data++ = I2C_BUS->RXDR;    // Принимаю данные
            Count++;
        }
    }

    I2C_BUS->CR2 |= I2C_CR2_STOP;                // Выдать стоп на шину
    while (I2C_BUS->ISR & I2C_ISR_BUSY);        // Ожидать выдачу стопа
    // Очищаю флаги - необходимо для дальнейшей работы шины
    I2C_BUS->ICR |= I2C_ICR_STOPCF;        // STOP флаг
    I2C_BUS->ICR |= I2C_ICR_NACKCF;        // NACK флаг
    // Если есть ошибки на шине - очищаю флаги
    if (I2C_BUS->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR)) {
        I2C_BUS->ICR |= I2C_ICR_ARLOCF;
        I2C_BUS->ICR |= I2C_ICR_BERRCF;
    }

  if (Count == length) return I2C_SUCCESS;
    return I2C_ERROR;
} 

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:11:55
gruffi
Нет варнингов не было, но подправил. Спасибо.
Ваш код работает, т.е. идет чтение, но только не понятно я задаю чтение с адреса 0х00, а он каждый раз при чтении выдает разный адрес регистра. Если устройство перезапустить, то при каждом чтении опять по тем же адресам идет...

Добавлено after 14 minutes 54 seconds:
Чтение идет в такой последовательности, при перезагрузке устройства (reg_addr = 0x00):
0x90, 0x08, 0x00, 0x20, 0xC5, 0x00, 0x00, 0x08, 0x4D...

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:26:17
uldemir
Похоже на проблему с передачей адреса регистра... Надо бы попробовать вставить флажок рядом с кодом

Код: Выделить всё

    if (I2C_BUS->ISR & I2C_ISR_TXIS) I2C_BUS->TXDR = reg_addr;    // Отправляю адрес регистра
и посмотреть выполняется ли он. А то может сразу происходит рестарт и выполняется current read, а не рандом.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:30:53
gruffi
да, так и есть TXIS не взлетает

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:38:50
uldemir
хм.. тогда надо сравнить с 16-битной функцией. Только что попробовал в своём коде сделать, чтобы читало начальные установки с 1-го адреса - вижу все данные сместились. Так что rd_reg16 - вроде работает как следует. Хотя всё различие, что передаётся один или два байта адреса...

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:48:31
gruffi
а можно посмотреть функцию rd_reg16?

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 14:50:24
uldemir
http://radiokot.ru/forum/viewtopic.php? ... 4#p3197984 под спойлером. Имелось в виду i2c_rd_reg16
Попробуйте у себя сделать чтение не с 0 адреса, а с другого и посмотрите, какая тогда последовательность прочитанных байтов будет.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 15:00:24
gruffi
Получается, что и здесь TXIS не взлетает...но в обоих вариантах взлетает при отладке, если пройти пошагово...

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 15:10:41
uldemir
но он там не сразу устанавливается, вроде. Ну, смеха для, перед передачей рестарта можно попробовать сформировать полный стоп. Для еепромки это должно быть без разницы - главное сделать фиктивную попытку записи по адресу, а потом оно с этого адреса и будет читать.

p.s. я в своей функции сделал счетчик переданных байт адреса и если он не равен 2 перед рестартом - выхожу с ошибкой. Но ошибка не появляется.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 16:22:19
gruffi
сделал STOP теперь читает 0xFF постоянно. Буду дальше смотреть. Спасибо большое.

Добавлено after 40 minutes 33 seconds:
uldemir, покажите пожалуйста настройку таймингов, т.к. я тайминги генерил через куб и при разных вариантах поведение одно и тоже. Может здесь собака порылась?!

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 16:31:27
uldemir
ммм. я тайминги каким-то экселем считал, что с сайта производителя скачивал. У меня такая строчка:
I2C_BUS->TIMINGR = (uint32_t)0x00100D14; /* (1) */
Тактируется от HSI.

Собственно, у меня самого сейчас с этим кодом возникли проблемы. Раз уж залез в этот девайс, решил добавить в меню еще одну настройку, в результате чего число параметров увеличилось и число записываемых байт перевалило размер страницы. Вот теперь что-то не получается сделать запись по-частям. Первую порцию записывает, а потом где-то виснет.

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 17:39:02
gruffi
уже склоняюсь к ногодрыгу :)...читал что у stm32 i2c глючный :)

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 17:58:43
dosikus
Глючный на F1 , на F0 все работает прекрасно.
Просто вы оба так и не въехали в сабж, хоть в RM все расписано от и до, и даже секвенции выложены.
Учитесь читать...

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 18:26:58
gruffi
Учимся :), но флаг TXIS так и не взлетает...

Re: stm32f030 + eeprom

Добавлено: Ср окт 04, 2017 18:33:38
dosikus
Завтра подробней, весь материал на работе.