|
Запись в Serial EEprom. |
|
|
|
Apr 11 2016, 13:01
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Записывая в память нужно следить чтобы не перейти страницу. Код #define USE_STATUS_REG 0 //doesn't help any way
void LOGGER_PageWrite(uint32_t address, uint32_t length, uint8_t *buffer) { #if USE_STATUS_REG uint32_t timer; #endif volatile uint32_t page_limit=0; volatile uint32_t bytes_to_fit=0; volatile uint32_t bytes_to_write=0;
//find a page limit for the address while (address > page_limit) { page_limit += 64; } //actual page limit page_limit--;
bytes_to_fit = page_limit - address; bytes_to_write = bytes_to_fit;
// Note!!!Every write operation demands a write enable!!! SPI_CSlow(); SPI_SendByte(SPIEEPROM_CMD_WREN); SPI_CShigh();
// start write SPI_CSlow(); // send write command SPI_SendByte(SPIEEPROM_CMD_WRITE); // send address SPI_SendByte(address>>8); SPI_SendByte(address&0x00FF); while(bytes_to_write--) { // send data to be written SPI_SendByte(*buffer++); } // stop write SPI_CShigh();
#if USE_STATUS_REG timer = LOGGER_DELAY; //wait for write operation to complete while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP) { if(!--timer) break; } #else //needs 5ms for page write Delay_us_sys(5000); #endif
if (bytes_to_fit <= length) { address += bytes_to_fit+1; bytes_to_write = length - bytes_to_fit;
// Note!!!Every write operation demands a write enable!!! SPI_CSlow(); SPI_SendByte(SPIEEPROM_CMD_WREN); SPI_CShigh();
// start write SPI_CSlow(); // send write command SPI_SendByte(SPIEEPROM_CMD_WRITE); // send address SPI_SendByte(address>>8); SPI_SendByte(address&0xFF); while(bytes_to_write--) { // send data to be written SPI_SendByte(*buffer++); } // stop write SPI_CShigh();
#if USE_STATUS_REG timer = LOGGER_DELAY; //wait for write operation to complete while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP) { if(!--timer) break; } #else //needs 5ms for page write Delay_us_sys(5000); #endif } } проверяю. пишу по середине большое количество байт чтоб перейти на другую страницу. Код uint8_t rxbuffer[50]; for (int i=0; i < 50; i++) { rxbuffer[i] = i+1; } LOGGER_PageWrite(80, 50, rxbuffer); и потом считываю. Код uint8_t txbuffer[50]; LOGGER_Read(80, 50,txbuffer); результаты такие: в адрессе 80-127 я вижу данные 1-47 и это правильно в адрессе 128-130 я вижу /0, 48, 49 то есть первый адресс следующей страницы не прописывается. целый день бьюсь над проблемой не могу понять в чем дело.
|
|
|
|
|
Apr 12 2016, 07:03
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
я извиняюсь немного непонятно это Код data += a; addr += a; len -= a; 'а' это bytes_to_write? переписал так Код void LOGGER_Write(uint32_t address, uint32_t lenght, uint8_t *data) { uint32_t timer; uint32_t bytes_to_write=0;
while(lenght) { if(((address & (PAGE_SIZE - 1)) + lenght) >= PAGE_SIZE) bytes_to_write = PAGE_SIZE - (address & (PAGE_SIZE - 1)); else bytes_to_write = lenght;
// Every write operation demands a write enable!!! SPI_CSlow(); SPI_SendByte(SPIEEPROM_CMD_WREN); SPI_CShigh();
// start write SPI_CSlow(); // send write command SPI_SendByte(SPIEEPROM_CMD_WRITE); // send address SPI_SendByte(address>>8); SPI_SendByte(address&0x00FF);
while(lenght--) { // send data to be written SPI_SendByte(*data++); } // stop write SPI_CShigh();
timer = LOGGER_DELAY; //wait for write operation to complete while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP) { if(!--timer) break; } data += bytes_to_write; address += bytes_to_write; lenght -= bytes_to_write; } } заходит в функцию но на выходе попадает в эксепшен. Код Default_Handler: b Default_Handler
.size Default_Handler, .-Default_Handler
|
|
|
|
|
Apr 12 2016, 07:07
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(aaarrr @ Apr 12 2016, 02:26)  Какой-то ужас, если честно. Полностью с Вами согласен! Сочувствую работодателю топикстартера. И так чуть оптимальнее: Код void eep_write(uint32_t addr, uint32_t len, uint8_t *data) { uint32_t i; while (len) { i = EEPROM_PAGE_SIZE - (addr & EEPROM_PAGE_SIZE - 1); if (i > len) i = len; //тут проверяем статус EEPROM, посылаем WREN и пишем (addr, i, data); data += i; addr += i; len -= i; } } И между SPI_CShigh() и SPI_CSlow() которые между каждыми двумя соседними командами, нужна хотя-бы минимальная задержка, чтобы микросхема успела почувствовать CS high. А точнее - задержка в соответствии с даташитом на микросхему (CS high минимум time или что-то в этом роде).
|
|
|
|
|
Apr 12 2016, 07:09
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Jenya7 @ Apr 12 2016, 10:03)  я извиняюсь немного непонятно это Код data += a; addr += a; len -= a; 'а' это bytes_to_write? Да, забыл отредактировать. Цитата(Jenya7 @ Apr 12 2016, 10:03)  переписал так Должно быть так: Код void LOGGER_Write(uint32_t address, uint32_t lenght, uint8_t *data) { uint32_t timer; uint32_t bytes_to_write=0;
while(lenght) { if(((address & (PAGE_SIZE - 1)) + lenght) >= PAGE_SIZE) bytes_to_write = PAGE_SIZE - (address & (PAGE_SIZE - 1)); else bytes_to_write = lenght;
// Every write operation demands a write enable!!! SPI_CSlow(); SPI_SendByte(SPIEEPROM_CMD_WREN); SPI_CShigh();
// start write SPI_CSlow(); // send write command SPI_SendByte(SPIEEPROM_CMD_WRITE); // send address SPI_SendByte(address>>8); SPI_SendByte(address&0x00FF);
address += bytes_to_write; lenght -= bytes_to_write;
while(bytes_to_write--) { // send data to be written SPI_SendByte(*data++); } // stop write SPI_CShigh();
timer = LOGGER_DELAY; //wait for write operation to complete while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP) { if(!--timer) break; } } }
|
|
|
|
|
Apr 12 2016, 08:05
|

Профессионал
    
Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877

|
Цитата Суд. Бракоразводный процесс. Судья спрашивает жену: - По какой причине вы хотите развестись с мужем? - Он меня как мужчина не удовлетворяет! Женский голос из зала: - Всех удовлетворяет, а её нет! Мужской голос из зала: - А её никто не удовлетворяет! Извините за флуд, но проверка регистра статуса - это рабочее решение (собственно, для того он там и есть). Ищите ошибку, кто такие LOGGER_DELAY, SPIEEPROM_ReadStatus() и SPIEEPROM_STATUS_WIP нам неведомо. И название микросхемы хорошо б сразу указывать. Тут, конечно, у многих навыки телепатии неплохие, но некрасиво это.
--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
|
|
|
|
|
Apr 12 2016, 08:16
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(aaarrr @ Apr 12 2016, 13:53)  Может, LOGGER_DELAY маловата? А зачем там вообще какая-то delay? Надо читать статус до тех пор пока не будет снят статус "занято". И делать это лучше не после, а перед операцией записи/стирания. Опять-же не выдерживается мин. время неактивности CS (ТС не читал даташит). Опять-же - не понятно как внутри устроена SPI_SendByte() у ТС, но очевидно что криво. Ибо, если она завершается сразу после записи байта данных в буферный регистр передатчика, то сразу после неё нельзя делать SPI_CShigh(); если же она завершается после опустошения сдвигового регистра передатчика, то это неоптимально (так как нет необходимости этого ждать внутри пакета байт команды).
|
|
|
|
|
Apr 12 2016, 08:27
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут. функции такие Код // commands #define SPIEEPROM_CMD_READ 0x03 // Read byte(s) #define SPIEEPROM_CMD_WRITE 0x02 // Write byte(s) #define SPIEEPROM_CMD_WREN 0x06 // Write Enable #define SPIEEPROM_CMD_WRDI 0x04 // Write Disable #define SPIEEPROM_CMD_RDSR 0x05 // Read Status Register #define SPIEEPROM_CMD_WRSR 0x01 // Write Status Register
// status register bit defines #define SPIEEPROM_STATUS_WIP 0x01 // Write in progress #define SPIEEPROM_STATUS_WEL 0x02 // Write enable #define SPIEEPROM_STATUS_BP0 0x04 // Block Protection 0 #define SPIEEPROM_STATUS_BP1 0x08 // Block Protection 1 #define SPIEEPROM_STATUS_WPEN 0x80 // Write Protect Enable
uint32_t SPI_TransferByte(uint32_t sendbyte) { uint32_t timeout = SPI_DELAY; /* Check that transmit buffer is empty */ while (!(SPI_USART->STATUS & USART_STATUS_TXBL)) { if(!--timeout) break; } SPI_USART->TXDATA = (uint32_t)sendbyte; /* Wait for transmitting to finished */ timeout = SPI_DELAY; while (!(SPI_USART->STATUS & USART_STATUS_TXC)) { if(!--timeout) break; } //return data; return majority32const(&SPI_USART->RXDATA); }
void SPI_SendByte(uint8_t sendbyte) { uint32_t timeout = SPI_DELAY;
USART_Tx(SPI_USART,sendbyte);
/* Wait for transmitting to finished */ while (!(SPI_USART->STATUS & USART_STATUS_TXC)) { if(!--timeout) break; } }
uint8_t SPIEEPROM_ReadStatus(void) { uint8_t status; SPI_CSlow(); // send read status register command SPI_SendByte(SPIEEPROM_CMD_RDSR); // get status register value status = SPI_TransferByte(0xFF); SPI_CShigh(); return status; } память CAT25256
Сообщение отредактировал Jenya7 - Apr 12 2016, 08:33
|
|
|
|
|
Apr 12 2016, 08:59
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(aaarrr @ Apr 12 2016, 14:26)  Выход по тайм-ауту в таких случаях желательно все же иметь. Но при аварии надо ошибку вернуть, конечно, а не просто вывалиться. Да, а потом ещё не забыть сделать обработку этих возвращаемых статусов ошибок во всех точках вызова (что обычно обязательно забывают где-нить сделать). Или вернуть этот статус выше и там обработать. В любом случае с этой ошибкой (таймаут неготовности) надо что-то делать. А что делать? Ведь если превышен таймаут (который выставлен правильно в соответствии с даташитом), то значит микросхема не функционирует. Вы все характеристики всех элементов в схеме проверяете на их соответствие заявленным в даташите, или всё же предполагаете, что она должна функционировать как обещал производитель? Я обычно тоже делаю контроль таймаута в таких случаях, но при возникновении события таймаута (превышения времени заявленного в даташите) не возвращаю какой-то статус, а вызываю событие "критическая ошибка" (так как это явно отказ аппаратуры). Обработчик такого события или просто выполняет аппаратный сброс или например входит в состояние "критическая ошибка" с индикацией этого состояния (в режиме отладки). Цитата(Jenya7 @ Apr 12 2016, 14:27)  таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут. Хорошо, вот наступил этот таймаут. Ваши действия? Что после этого делать-то?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|