Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Чтение и запись во внешнюю память.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Jenya7
Это функции чтения/записи.
Код
void SPIEEPROM_WriteInt(uint32_t addr, uint32_t *ival)
{
  SPIEEPROM_Write(addr,sizeof(uint32_t),(uint8_t*) ival);
}

uint32_t SPIEEPROM_ReadInt(uint32_t addr)
{
    uint32_t value;
    SPIEEPROM_Read(addr, sizeof(uint32_t), (uint8_t*)&value);
    return value;
}

void SPIEEPROM_WriteFloat(uint32_t addr, float *fval)  
{
  SPIEEPROM_Write(addr,sizeof(float),(uint8_t*) fval);
}

float SPIEEPROM_ReadFloat(uint32_t addr)
{
    float value;
    SPIEEPROM_Read(addr, sizeof(float), (uint8_t*)&value);
    return value;
}

А так я тестирую.
Код
uint32_t adr;
if(argument1 == NULL)
  UART_SendString(UART0,msg_misarg);
else
{
  adr = atoi(argument1);
  if(argument2 == NULL) //read operation
  {
      #ifdef SPI_INT
      uint32_t ival = SPIEEPROM_ReadInt(adr);
      UART_SendInt(UART0,ival);
      #endif
      #ifdef SPI_FLOAT
       float fval = SPIEEPROM_ReadFloat(adr);
        UART_SendFloat(UART0,fval,2);
      #endif
    }
    else  //write operation
    {                    
        #ifdef SPI_INT
         uint32_t ival = atoi(argument2);
        SPIEEPROM_WriteInt(adr, &ival);
         #endif
         #ifdef SPI_FLOAT
          float fval = atof(argument2);
          SPIEEPROM_WriteFloat(adr, &fval);
          #endif
                    
     }
}

float пишется-читается прекрасно.
а вот с uint32_t непонятное явление - пишет (или читает?) неправильно.
вот например
запись - чтение
100 - 255
300 - 511
1000 - 1023
Сижу второй день над проблемой не могу понять где собака порылась.
mcheb
Цитата(Jenya7 @ Jun 25 2015, 08:43) *
SPIEEPROM_Write(addr,sizeof(uint32_t),(uint8_t*) ival);

А это что за чудо?
Jenya7
Цитата(mcheb @ Jun 25 2015, 11:52) *
А это что за чудо?

сделал так
SPIEEPROM_Write(addr, 4, (uint8_t*) ival);
не помогло

mempfis_
Цитата(Jenya7 @ Jun 25 2015, 09:26) *
сделал так SPIEEPROM_Write(addr, 4, (uint8_t*) ival); не помогло


Никто не может догадаться какой код у функции SPIEEPROM_Write(). Если у вас там serial eeprom то там важно знать адрес и размер блока данных.
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 13:29) *
Никто не может догадаться какой код у функции SPIEEPROM_Write(). Если у вас там serial eeprom то там важно знать адрес и размер блока данных.

но float то пишется и читается значит SPIEEPROM_Write() работает корректно.
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 10:41) *
но float то пишется и читается значит SPIEEPROM_Write() работает корректно.


ОК. А в UART_SendInt(UART0,ival); нет ошибок?
Какой тип eeprom используется и по каким адресам пишется int и float?
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 13:55) *
ОК. А в UART_SendInt(UART0,ival); нет ошибок?
Какой тип eeprom используется и по каким адресам пишется int и float?

я ставлю break point до UART_SendInt(UART0,ival);
пишу в один и тот же адрес. пробовал разные адреса. IAR сошел с ума? интерпретирует uint32_t неправильно?
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 11:18) *
я ставлю break point до UART_SendInt(UART0,ival);
пишу в один и тот же адрес. пробовал разные адреса. IAR сошел с ума? интерпретирует uint32_t неправильно?


Может для ускорения решения проблемы приведёте код базовых функций чтения/записи из/в eeprom, функций отправки int/float в uart, назовёте тип eeprom и конкретные адреса по которым происходит запись/чтение? Без этих данных мало чем можно помочь.
Ещё можно указать что за IAR и проверить размер стека программы.


Jenya7
Цитата(mempfis_ @ Jun 25 2015, 14:29) *
Может для ускорения решения проблемы приведёте код базовых функций чтения/записи из/в eeprom, функций отправки int/float в uart, назовёте тип eeprom и конкретные адреса по которым происходит запись/чтение? Без этих данных мало чем можно помочь.
Ещё можно указать что за IAR и проверить размер стека программы.


это функции

Код
void SPIEEPROM_Write(uint32_t address, uint32_t lenght, uint8_t *buffer)
{
    // Note!!!Every write operation demands a write enable!!!
    SPI2_CSlow();
    SPI_SendByte(USART2,SPIEEPROM_CMD_WREN);
    SPI2_CShigh();

    // start write
    SPI2_CSlow();
    // send write command
    SPI_SendByte(USART2,SPIEEPROM_CMD_WRITE);
    // send address
    SPI_SendByte(USART2,address>>8);
    SPI_SendByte(USART2,address&0x00FF);
    while(lenght--)
    {
      // send data to be written
      SPI_SendByte(USART2,*buffer++);
    }
    // stop write
    SPI2_CShigh();
}

void SPIEEPROM_Read(uint32_t address, uint32_t lenght, uint8_t *buffer)
{
    if(lenght>PAGE_SIZE)
        return;
    uint32_t data;
    // start read
    SPI2_CSlow();
    // send command
    SPI_SendByte(USART2,SPIEEPROM_CMD_READ);
    // send address
    SPI_SendByte(USART2,address>>8);
    SPI_SendByte(USART2,address&0x00FF);
    // read contents of memory address
    while(lenght--)
    {
        data = SPI_TransferByte(USART2,0x00);
        *buffer++ = data;
    }
    // stop read
    SPI2_CShigh();
}


IAR V7.2.
size_cstack__ = 0x400;
память CAT25256

вопрос почему float пишется-читается правильно а uint32_t нет.
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 11:55) *
IAR V7.2.
size_cstack__ = 0x400;
память CAT25256
вопрос почему float пишется-читается правильно а uint32_t нет.


По структуре функций - при чтении похоже всё нормально. А вот при записи не хватает ожидания завершения записи - контроля бита 0 (маска 0x01 в статус-регистре) сразу после SPI2_CShigh();. Любое обращение к памяти во время записи может сбить запись. Также я не увидел контроля пересечения границы страницы при записи данных. Если Вы вдруг захотите записать 4 байта начиная с адреса скажем 61 (мене чем за 4 байта до границы страницы) то получите сюрприз при чтении.
SPI_SendByte(USART2,SPIEEPROM_CMD_READ); отправляет байт в SPI и паралельно в UART?
SPI_TransferByte(USART2,0x00); - читает байт из SPI и паралельно отправляет байт в UART?
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 15:10) *
По структуре функций - при чтении похоже всё нормально. А вот при записи не хватает ожидания завершения записи - контроля бита 0 (маска 0x01 в статус-регистре) сразу после SPI2_CShigh();. Любое обращение к памяти во время записи может сбить запись. Также я не увидел контроля пересечения границы страницы при записи данных. Если Вы вдруг захотите записать 4 байта начиная с адреса скажем 61 (мене чем за 4 байта до границы страницы) то получите сюрприз при чтении.
SPI_SendByte(USART2,SPIEEPROM_CMD_READ); отправляет байт в SPI и паралельно в UART?
SPI_TransferByte(USART2,0x00); - читает байт из SPI и паралельно отправляет байт в UART?


спасибо за замечания. исправлю. однако это не объясняет проблему.
я думал что для этой памяти не важно пересечение границы страницы. но я писал в разные адреса 10, 20,100.
я пишу-читаю с терминала, после записи проходит достаточно времени.
у меня USART2 настроен как SPI.
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 12:40) *
я думал что для этой памяти не важно пересечение границы страницы. но я писал в разные адреса 10, 20,100.
я пишу-читаю с терминала, после записи проходит достаточно времени.
у меня USART2 настроен как SPI.


Пересечение границы очень важно и его нельзя упускать из виду. Также важно отследить завершение записи.
Стоит также проконтролировать осциллографом запись в работающем и неработающем вариантах. Может быть там несанкционированные дёргания CS или искаженные символы при передаче адреса/данных.
Не пробовали софтовый SPI прикрутить? Может быть проблемы с аппаратным?
CODE
//-------------------------------------------
unsigned char SPIWriteChar(unsigned char cmd)
{
unsigned char i;
unsigned char recv;
recv = 0;

for(i=0; i<8; i++)
{
if((cmd&0x80) != 0)
{
SPI_PORT_SET = MOSI;
}
else
{
SPI_PORT_CLR = MOSI;
}

SPI_PORT_SET = SCK;

recv<<=1;
if((SPI_PIN & MISO) != 0)
{
recv|=0x01;
}

SPI_PORT_CLR = SCK;

cmd<<=1;
}
return recv;
}
//-------------------------------------------


Jenya7
Цитата(mempfis_ @ Jun 25 2015, 16:11) *
Пересечение границы очень важно и его нельзя упускать из виду. Также важно отследить завершение записи.
Стоит также проконтролировать осциллографом запись в работающем и неработающем вариантах. Может быть там несанкционированные дёргания CS или искаженные символы при передаче адреса/данных.
Не пробовали софтовый SPI прикрутить? Может быть проблемы с аппаратным?
CODE
//-------------------------------------------
unsigned char SPIWriteChar(unsigned char cmd)
{
unsigned char i;
unsigned char recv;
recv = 0;

for(i=0; i<8; i++)
{
if((cmd&0x80) != 0)
{
SPI_PORT_SET = MOSI;
}
else
{
SPI_PORT_CLR = MOSI;
}

SPI_PORT_SET = SCK;

recv<<=1;
if((SPI_PIN & MISO) != 0)
{
recv|=0x01;
}

SPI_PORT_CLR = SCK;

cmd<<=1;
}
return recv;
}
//-------------------------------------------


я смотрел и осциллографом и Logic Analizer все красиво.

кстати а какой алгоритм проверки пересечения границы страницы?
если я пишу uint32_t и следующая запись приходится на адрес 62 то что я перескакиваю на адрес 64? а при чтении как я учитываю это?
mempfis_
Цитата
я смотрел и осциллографом и Logic Analizer все красиво.


т.е. хотите сказать что адрес и данные корректные - что хотите записать то и видите на осциллографе?

Цитата
кстати а какой алгоритм проверки пересечения границы страницы?
если я пишу uint32_t и следующая запись приходится на адрес 62 то что я перескакиваю на адрес 64? а при чтении как я учитываю это?


Мне приходилось записывать блоки данных такой длины, что они вписывались в страницу без остатка.
Если данные не влезают на текущую страницу, то надо вычислять сколько осталось до конца страницы, записывать столько байт, сколько влезет на текущую старницу, остаток дописывать на следующую страницу.
Напр. адрес 446, пишем 4 байта. 446/64 = 6, 446%64 = 62. 64-62 = 2 - столько влезет на текущую страницу. Т.о. с адреса 446 Вы запишите 2 байта, а с адреса 448 ещё 2 байта.
А вот читать Вы можете непрерывно требуемое кол-во байт с любого адреса.
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 16:32) *
т.е. хотите сказать что адрес и данные корректные - что хотите записать то и видите на осциллографе?

Мне приходилось записывать блоки данных такой длины, что они вписывались в страницу без остатка.
Если данные не влезают на текущую страницу, то надо вычислять сколько осталось до конца страницы, записывать столько байт, сколько влезет на текущую старницу, остаток дописывать на следующую страницу.
Напр. адрес 446, пишем 4 байта. 446/64 = 6, 446%64 = 62. 64-62 = 2 - столько влезет на текущую страницу. Т.о. с адреса 446 Вы запишите 2 байта, а с адреса 448 ещё 2 байта.
А вот читать Вы можете непрерывно требуемое кол-во байт с любого адреса.


нет. данные неправильные но сигналы красивые.
пока проблему решил так - просто делаю кастинг с float на uint32_t но это конечно ужасно.
спасибо за алгоритм,попробую реализовать у меня точно данные залезут за границу.
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 13:58) *
пока проблему решил так - просто делаю кастинг с float на uint32_t но это конечно ужасно.


Может быть проблемы с atoi(argument1/2); ?
Вы не пробовали отправлять в эхо команд и результаты работы функций atoi/atof?
Что если не использовать аргументы а просто записывать по фиксированным адресам фиксированные данные.
Или завести static int adr, value и инкрементиоровать их с каждой командой на запись.

Мне приходилось работать как минимум с 2мя производителями памяти на 3х разных архитектурах процессоров. Были программные проблемы, но проблем с памятью никогда не было при выдерживании корректной процедуры записи.
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 17:13) *
Может быть проблемы с atoi(argument1/2); ?
Вы не пробовали отправлять в эхо команд и результаты работы функций atoi/atof?
Что если не использовать аргументы а просто записывать по фиксированным адресам фиксированные данные.
Или завести static int adr, value и инкрементиоровать их с каждой командой на запись.

Мне приходилось работать как минимум с 2мя производителями памяти на 3х разных архитектурах процессоров. Были программные проблемы, но проблем с памятью никогда не было при выдерживании корректной процедуры записи.


попробовал прописать напрямую адрес и дату. та же проблема. это что то в IAR.
Сергей Борщ
В функциях из первого сообщения ошибок нет. Как вы понимаете, число с плавающей точкой занимает те же 4 байта, что и 32-битное целое. Поэтому компилятор должен был сгенерить идентичный код для SPIEEPROM_WriteInt() и SPIEEPROM_WriteFloat(), а также для пары функций чтения. Я бы на вашем месте для начала проверил корректность работы функции UART_SendInt() примерно так:
Код
    else  //write operation
    {                    
        #ifdef SPI_INT
         uint32_t ival = atoi(argument2);
      UART_SendInt(UART0,ival);   // <------------------
        SPIEEPROM_WriteInt(adr, &ival);
Отладчик в точке останова может и не показать правильное значение переменной (если эта переменная на момент останова еще находится в регистре, например). Тут надо очень внимательно смотреть дизассемблированный код, чтобы понять - где именно на данной команде находится значение переменной.
Jenya7
Цитата(Сергей Борщ @ Jun 25 2015, 17:25) *
В функциях из первого сообщения ошибок нет. Как вы понимаете, число с плавающей точкой занимает те же 4 байта, что и 32-битное целое. Поэтому компилятор должен был сгенерить идентичный код для SPIEEPROM_WriteInt() и SPIEEPROM_WriteFloat(), а также для пары функций чтения. Я бы на вашем месте для начала проверил корректность работы функции UART_SendInt() примерно так:
Код
    else  //write operation
    {                    
        #ifdef SPI_INT
         uint32_t ival = atoi(argument2);
      UART_SendInt(UART0,ival);   // <------------------
        SPIEEPROM_WriteInt(adr, &ival);
Отладчик в точке останова может и не показать правильное значение переменной (если эта переменная на момент останова еще находится в регистре, например). Тут надо очень внимательно смотреть дизассемблированный код, чтобы понять - где именно на данной команде находится значение переменной.


Сергей сделал как вы советовали. Вижу в терминале правильное значение. В том то и весь маразм - функции для float и uint32_t абсолютно одинаковы за исключением самой переменной.
Jenya7
OMG!!!
нашел проблему. в SPIEEPROM_Read() заменил все SPI_SendByte на SPI_TransferByte().
mempfis_
Цитата(Jenya7 @ Jun 25 2015, 16:37) *
OMG!!!
нашел проблему. в SPIEEPROM_Read() заменил все SPI_SendByte на SPI_TransferByte().

1111493779.gif
Мои поздравления.

Приведите тогда уж код обеих функций - посмотрим чем они отличаются. И почему с одной не работает, а со второй работает.
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 19:42) *
1111493779.gif
Мои поздравления.

Приведите тогда уж код обеих функций - посмотрим чем они отличаются. И почему с одной не работает, а со второй работает.


Код
void SPI_SendByte(USART_TypeDef  *usart,uint8_t sendbyte)
{
    /* Check that transmit buffer is empty */
    while (!(usart->STATUS & USART_STATUS_TXBL));

    usart->TXDATA = (uint32_t)sendbyte;

    /* Wait for transmitting to finished */
  while (!(usart->STATUS & USART_STATUS_TXC));
}


uint32_t SPI_TransferByte(USART_TypeDef *usart,uint32_t sendbyte)
{
   /* Check that transmit buffer is empty */
  while (!(usart->STATUS & USART_STATUS_TXBL));

  usart->TXDATA = (uint32_t)sendbyte;

  /* Wait for transmitting to finished */
  while (!(usart->STATUS & USART_STATUS_TXC));

  //return data;
    return majority32const(&usart->RXDATA);

}
mempfis_
Я во всех примерах работы с SPI всех мк с которыми работал видел чтение регистра данных после завершения передачи. Даже если результат нафиг не нужен. С STM32 работал но Hard SPI пока не использовал. Буду знать что принцип работы с ним схож с другими мк.
Jenya7
Цитата(mempfis_ @ Jun 25 2015, 21:46) *
Я во всех примерах работы с SPI всех мк с которыми работал видел чтение регистра данных после завершения передачи. Даже если результат нафиг не нужен. С STM32 работал но Hard SPI пока не использовал. Буду знать что принцип работы с ним схож с другими мк.

Но что интересно float читался правильно. Наверно надо очищать приемный буфер в любом случае, иначе что то там глючит.
Сергей Борщ
Цитата(Jenya7 @ Jun 25 2015, 16:37) *
нашел проблему. в SPIEEPROM_Read() заменил все SPI_SendByte на SPI_TransferByte().
Есть некоторые сомнения. Либо у вас там теперь четное количество ошибок. Мы же согласились, что и для целого, и для числа с плавающей точкой SPIEEPROM_Read() и SPIEEPROM_Write() вызываются с идентичными параметрами. Если бы проблема была (только) внутри функции чтения, то она проявлялась бы и для целого, и для числа с плавающей точкой. Я еще в предыдущем сообщении хотел предложить вам попробовать записать/прочитать с помощью SPIEEPROM_Write()/SPIEEPROM_Read() массив из 10-20 байтов - на нем ошибка была бы виднее.

Кстати, а что делает последний параметр в функции UART_SendFloat(UART0,fval,2)? Уж не количество ли знаков после запятой он указывает? Тогда вполне вероятно, что ошибку чтения в самом младшем байте вы могли просто не увидеть, потому что эти биты просто не попадают на экран.
Jenya7
Цитата(Сергей Борщ @ Jun 26 2015, 11:03) *
Есть некоторые сомнения. Либо у вас там теперь четное количество ошибок. Мы же согласились, что и для целого, и для числа с плавающей точкой SPIEEPROM_Read() и SPIEEPROM_Write() вызываются с идентичными параметрами. Если бы проблема была (только) внутри функции чтения, то она проявлялась бы и для целого, и для числа с плавающей точкой. Я еще в предыдущем сообщении хотел предложить вам попробовать записать/прочитать с помощью SPIEEPROM_Write()/SPIEEPROM_Read() массив из 10-20 байтов - на нем ошибка была бы виднее.

Кстати, а что делает последний параметр в функции UART_SendFloat(UART0,fval,2)? Уж не количество ли знаков после запятой он указывает? Тогда вполне вероятно, что ошибку чтения в самом младшем байте вы могли просто не увидеть, потому что эти биты просто не попадают на экран.

Сергей вы как всегда правы. Третий параметр это количество знаков после запятой. Поэтому мы не видели ошибку.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.