Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: хранение данных во флэш epcs4
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Wic
Говорят, что можно средствами NIOS, читать и писать данные во флэшку, с которой производится конфигурирование плис. Но уж очень доступная документация не позволяет легко понять как же это делать. Попробовал разобраться по исходникам, что идут в составе BSP, но со всеми струкутрами и функциями так и не понял как же это должно работать.
Цель стоит простая хранить там серийник устройства и несколько параметров. Можно ли такое сделать?
Чего почитать чтобы понять как же это заставить работать, или пример посмотреть на крайний случай


исходя из файлов заголовков инициализация проходит при помощи

Код
int alt_epcs_flash_init(alt_flash_epcs_dev* flash);

где
Код
struct alt_flash_epcs_dev
{
  alt_flash_dev dev;

  alt_u32 register_base;
  alt_u32 size_in_bytes;
  alt_u32 silicon_id;
  alt_u32 page_size;
};
// и тут же далее по ссылке  alt_flash_dev
struct alt_flash_dev
{
  alt_llist                 llist;
  const char*               name;
  alt_flash_open            open;
  alt_flash_close           close;
  alt_flash_write           write;
  alt_flash_read            read;
  alt_flash_get_flash_info  get_info;
  alt_flash_erase_block     erase_block;
  alt_flash_write_block     write_block;
  void*                     base_addr;
  int                       length;
  int                       number_of_regions;
  flash_region              region_info[ALT_MAX_NUMBER_OF_FLASH_REGIONS];
};

мой код
Код
//включаю файлы заголовков
#define ALT_USE_EPCS_FLASH
#include <altera_avalon_epcs_flash_controller.h>
alt_flash_epcs_dev mem;
int a;
//задаю название контролерра
mem.dev.name=EPCS_FLASH_CONTROLLER_0_NAME;
// пытаюсь инициализировать его
a = alt_epcs_flash_init(mem);
// и прочитать
ret_code = alt_epcs_flash_read(mem->dev, 0, data_array_name, 16);

А он мне в ответ
Цитата
hello_world_small.c:309: error: incompatible type for argument 1 of 'alt_epcs_flash_init'
hello_world_small.c:310: error: invalid type argument of '->'

при
Код
ret_code = alt_epcs_flash_read(mem.dev, 0, data_array_name, 16);

Цитата
hello_world_small.c:310: error: incompatible type for argument 1 of 'alt_epcs_flash_read'
Stewart Little
Кода-то использовал такую тестилку для доступа в EPCS:


Код
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "epcs_commands.h"

int main (void)
{ alt_flash_fd* fd;

  alt_u8 epcs_status;

  epcs_status = epcs_read_status_register(EPCS_FLASH_CONTROLLER_BASE);

  fd = alt_flash_open_dev("/dev/epcs_flash_controller");
  if(fd != NULL)
    { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0x01);
      alt_flash_close_dev(fd);
    }
  else { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0x55);
       }

  while (1)
  ;
}


ЕМНИП, если при организации доступа к EPCS'ке использовать сокращенные версии драйверов (установлена галка Enable reduced device drivers в bsp), то возникает проблема, поскольку при использовании сокращенных драйверов в проект не будет добавляться библиотека для работы с EPCS.
Поэтому нужно специально указать, что эта библиотека должна использоваться в проекте.
Чтобы сделать это, надо открыть файл alt_sys_init.c, найти там строку
#include "altera_avalon_epcs_flash_controler.h",
и перед ней вставить
#define ALT_USE_EPCS_FLASH
Wic
Цитата(Stewart Little @ Jul 1 2011, 18:55) *
Чтобы сделать это, надо открыть файл alt_sys_init.c, найти там строку
#include "altera_avalon_epcs_flash_controler.h",
и перед ней вставить
#define ALT_USE_EPCS_FLASH

такое действие убивает систему, она перестает стартовать. памяти 20кбайт ончип рам
Wic
После прочтения темы Решил не пользоваться HAL, а использовать драйвер "epcs_commands.h".

Написал такой код

Код
#define EPCS_ADR 523776

alt_u8 data[15];
alt_u32 j;

    j = epcs_read_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR, &data, 15);

    for(i=0;i<15;i++)
    {
        printf("%x\n",data[i]);
    }


    data[0]=0x00;
    data[1]=0x01;
    data[2]=0x02;
    data[3]=0x03;
    data[4]=0x04;
    data[5]=0x05;
    data[6]=0x06;
    data[7]=0x10;
    data[8]=0x20;
    data[9]=0x30;
    data[10]=0x40;
    data[11]=0x50;
    data[12]=0x6C;
    data[13]=0xAA;
    data[14]=0xFF;


    j = epcs_write_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR , &data, 15);

    j = epcs_read_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR, &data, 15);

    for(i=0;i<15;i++)
    {
        printf("%x\n",data[i]);
    }


В пятницу всё прекрасно работало. Три дня меня не было, прихожу - часть переменных читается нулями, а в части лежат нужные данные. Пытаюсь писать туда нужные значения. Ничего не меняется.

Подскажите в чем может быть причина.
vadimuzzz
вот пример:
CODE

...
unsigned char e_buf[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
...
epcs_write_enable(EPCS_FLASH_CONTROLLER_0_BASE+EPCS_FLASH_CONTROLLER_0_REGISTER_
OFFSET);
epcs_sector_erase(EPCS_FLASH_CONTROLLER_0_BASE+EPCS_FLASH_CONTROLLER_0_REGISTER_
OFFSET,EPCS_SET_OFFS);
epcs_read_buffer(EPCS_FLASH_CONTROLLER_0_BASE+EPCS_FLASH_CONTROLLER_0_REGISTER_O
FFSET,EPCS_SET_OFFS,e_buf,16);
for(t=0;t<16;t++)
alt_printf("e_buf[%x]=%x\n",t,e_buf[t]);
for(t=0;t<16;t++)
e_buf[t] = t;
epcs_write_buffer(EPCS_FLASH_CONTROLLER_0_BASE+EPCS_FLASH_CONTROLLER_0_REGISTER_
OFFSET,EPCS_SET_OFFS,e_buf,16);
for(t=0;t<16;t++)
alt_printf("e_buf[%x]=%x\n",t,e_buf[t]);
for(t=0;t<16;t++)
e_buf[t]=0;
for(t=0;t<16;t++)
alt_printf("e_buf[%x]=%x\n",t,e_buf[t]);
epcs_read_buffer(EPCS_FLASH_CONTROLLER_0_BASE+EPCS_FLASH_CONTROLLER_0_REGISTER_O
FFSET,EPCS_SET_OFFS,e_buf,16);
for(t=0;t<16;t++)
alt_printf("e_buf[%x]=%x\n",t,e_buf[t]);

можете его прогнать и выхлоп сюда, сравним с моим
Wic
Задал #define EPCS_SET_OFFS 0
Вот результат. И один вопрос, как работает epcs_sector_erase, сколько не пытался его запустить, не получал
никаких изменений.

CODE

e_buf[0]=ff
e_buf[1]=ff
e_buf[2]=ff
e_buf[3]=ff
e_buf[4]=ff
e_buf[5]=ff
e_buf[6]=ff
e_buf[7]=ff
e_buf[8]=ff
e_buf[9]=ff
e_buf[a]=ff
e_buf[b]=ff
e_buf[c]=ff
e_buf[d]=ff
e_buf[e]=ff
e_buf[f]=ff
e_buf[0]=0
e_buf[1]=1
e_buf[2]=2
e_buf[3]=3
e_buf[4]=4
e_buf[5]=5
e_buf[6]=6
e_buf[7]=7
e_buf[8]=8
e_buf[9]=9
e_buf[a]=a
e_buf[b]=b
e_buf[c]=c
e_buf[d]=d
e_buf[e]=e
e_buf[f]=f
e_buf[0]=0
e_buf[1]=0
e_buf[2]=0
e_buf[3]=0
e_buf[4]=0
e_buf[5]=0
e_buf[6]=0
e_buf[7]=0
e_buf[8]=0
e_buf[9]=0
e_buf[a]=0
e_buf[b]=0
e_buf[c]=0
e_buf[d]=0
e_buf[e]=0
e_buf[f]=0
e_buf[0]=0
e_buf[1]=1
e_buf[2]=2
e_buf[3]=3
e_buf[4]=4
e_buf[5]=5
e_buf[6]=6
e_buf[7]=7
e_buf[8]=8
e_buf[9]=9
e_buf[a]=a
e_buf[b]=b
e_buf[c]=c
e_buf[d]=d
e_buf[e]=e
e_buf[f]=f
vadimuzzz
Цитата(Wic @ Oct 25 2011, 16:45) *
Вот результат.

все правильно
Цитата
И один вопрос, как работает epcs_sector_erase, сколько не пытался его запустить, не получал
никаких изменений.

стирает сектор с указанным смещением. смещение в байтах
Wic
После того как делаю epcs_sector_erase, проходит запись.
Обязательно ли чистить сектор перед записью?
Посмотрел исходник "epcs_commands.c", немного вызывает сомнения того, что при записи программа не ждет окончания записи команды. Даже есть интересный комментарий для комманды чтения.
CODE
alt_32 epcs_read_buffer(alt_u32 base, int offset, alt_u8 *dest_addr, int length)
{
alt_u8 read_command[4];

read_command[0] = epcs_read;
read_command[1] = (offset >> 16) & 0xFF;
read_command[2] = (offset >> 8) & 0xFF;
read_command[3] = offset & 0xFF;

#if 0
/* If a write is in progress, fail. */
if (epcs_test_wip(base))
return 0;
#endif
/* I don't know why this is necessary, since I call await-wip after
* all writing commands.
*/
epcs_await_wip_released(base);

alt_avalon_spi_command(
base,
0,
sizeof(read_command) / sizeof(*read_command),
read_command,
length,
(alt_u8*)dest_addr,
0
);

return length;
}


А вот для записи нет строчки, после отправки команды на запись
Код
  epcs_await_wip_released(base);


Буду пробовать править исходники.

UPD попытка править исходники ничего не дала. Иногда пишет без epcs_sector_erase. Но как то не хочется чистить сектор для небольшой правки. Но вот понять, что ей нужно чтобы писать без очистки пока не могу.
vadimuzzz
Цитата(Wic @ Oct 26 2011, 11:39) *
Но как то не хочется чистить сектор для небольшой правки. Но вот понять, что ей нужно чтобы писать без очистки пока не могу.

если выбранный для записи фрагмент чист (забит 0xff), то можно не стирать сектор. но более надежный вариант: считать в буфер/изменить/стереть сектор/записать в буфер.
Цитата
А вот для записи нет строчки, после отправки команды на запись

есть она там. автор недоумевает, почему она нужна перед чтением буфера. мне тоже непонятно.
смотрим описание на флешку (spansion, но не суть):
Цитата
WIP | Write in Progress | 1 = Device Busy. A Write Status Register, program, or erase operation is in progress

т.е. epcs_await_wip_released(base); должна стоять в конце процедур epcs_write_status_register(), epcs_write_buffer(), epcs_sector_erase()
она там стоит, но почему-то этого недостаточно
Wic
Спасибо за объяснение =)
Теперь просто храню массив с данными в памяти, который читаю при старет, а если что то поменялось, то пишу его во флэш командой
Код
void wright_data_to_epcs()
{
    epcs_write_enable(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET);
    epcs_sector_erase(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR);
    j = epcs_write_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR , data, DATA_EPCS_SIZE);
    return;
}


stu
В описании EPCS написано, что EPCS4 с 0,15 um тех. процессом может работать с fast read(40 МГц), но в мегвизарде такая опция для EPCS4 отключена. Если вместо 20 подать 40 она работать будет? Может, кто пробовал...

Сам тест описал. Норм работает... хоть 20, хоть 40 МГц
AlexMad
Цитата(Wic @ Oct 26 2011, 13:50) *
Спасибо за объяснение =)
Теперь просто храню массив с данными в памяти, который читаю при старет, а если что то поменялось, то пишу его во флэш командой


Делаю также, но в какой-то момент возникли проблемы.
Пока не уверен, что это не я в коде где-то накосячил, но в поисках проблем возник вопрос:
А какая допустимая величина буфера для epcs_write_enable ?
vadimuzzz
Цитата(AlexMad @ Feb 24 2014, 18:29) *
А какая допустимая величина буфера для epcs_write_enable ?

epcs_write_enable разрешает запись. имелось в виду epcs_write_buffer ? тогда он не больше размера страницы
AlexMad
Цитата(vadimuzzz @ Feb 25 2014, 14:21) *
epcs_write_enable разрешает запись. имелось в виду epcs_write_buffer ? тогда он не больше размера страницы


Да, Вы меня правильно поняли. Про размер страницы - спасибо, так и думал. Получается, что глюки у меня были из-за этого. Как всегда малое изменение влечет большие проблемы. У меня в структуре были переменные типа char, для удобства адресации в другом участке кода поменял их на long int. Отсюда увеличение размера структуры и глюки с записью.
В общем Спасибо за подсказку.
dim99
Внесу свои пять копеек по поводу хранения данных в EPCS16 для Q13.
В таком случае можно выставить Reduced Device Drivers и хорошо сэкономить на памяти.

Код
#include "epcs_commands.h"

// адрес EPCS контроллера
const alt_u32 EPCS_ADDR = EPCS_FLASH_CONTROLLER_0_BASE + EPCS_FLASH_CONTROLLER_0_REGISTER_OFFSET;
// смещение параметров модуля в EPCS - 30 страница для хранения
const alt_u32 EPCS_PARAMS_OFFSET = 65536*30;
// режим байтов для EPCS
const alt_u32 EPCS_BYTE_MODE = 0;

void LoadEpcsData(alt_u8* destBuf, int length)
{
    epcs_read_buffer(EPCS_ADDR, EPCS_PARAMS_OFFSET, destBuf, length, EPCS_BYTE_MODE);
}

void SaveEpcsData(alt_u8* srcBuf, int length)
{
    epcs_write_enable(EPCS_ADDR);
    epcs_sector_erase(EPCS_ADDR, EPCS_PARAMS_OFFSET, EPCS_BYTE_MODE);
    epcs_write_buffer(EPCS_ADDR, EPCS_PARAMS_OFFSET, srcBuf, length, EPCS_BYTE_MODE);
}


Единственное не до конца понял, что за режим four_bytes_mode.
Но стабильно работает при EPCS_BYTE_MODE = 0;
Kuzmi4
Цитата(dim99 @ Aug 18 2014, 13:43) *
...
Единственное не до конца понял, что за режим four_bytes_mode.

Есть новые камни - Quad-Serial Configuration (EPCQ) Devices, они позволяют не по одному проводу данные гонять а по 4м сразу. Этот мод как раз для них cool.gif
FLTI
Цитата(Wic @ Oct 25 2011, 11:51) *
После прочтения темы Решил не пользоваться HAL, а использовать драйвер "epcs_commands.h".

Написал такой код

Код
#define EPCS_ADR 523776

alt_u8 data[15];
alt_u32 j;

     j = epcs_read_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR, &data, 15);

     for(i=0;i<15;i++)
     {
         printf("%x\n",data[i]);
     }


     data[0]=0x00;
     data[1]=0x01;
     data[2]=0x02;
     data[3]=0x03;
     data[4]=0x04;
     data[5]=0x05;
     data[6]=0x06;
     data[7]=0x10;
     data[8]=0x20;
     data[9]=0x30;
     data[10]=0x40;
     data[11]=0x50;
     data[12]=0x6C;
     data[13]=0xAA;
     data[14]=0xFF;


     j = epcs_write_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR , &data, 15);

     j = epcs_read_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR, &data, 15);

     for(i=0;i<15;i++)
     {
         printf("%x\n",data[i]);
     }


В пятницу всё прекрасно работало. Три дня меня не было, прихожу - часть переменных читается нулями, а в части лежат нужные данные. Пытаюсь писать туда нужные значения. Ничего не меняется.

Подскажите в чем может быть причина.

Возможно, что причина в этой строчке?
j = epcs_write_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR , &data, 15);
Что Вы хотели с её помощью получить?
Как можно переменной j присваивать действие процедуры epcs_write_buffer ?
Это корректно?
Ведь в следующей строке этой же переменной j присваиватся результат действия процедуры epcs_read_buffer.
_Anatoliy
Цитата(FLTI @ Apr 23 2015, 10:40) *
Возможно, что причина в этой строчке?
j = epcs_write_buffer(EPCS_FLASH_BASE+EPCS_FLASH_REGISTER_OFFSET, EPCS_ADR , &data, 15);
Что Вы хотели с её помощью получить?
Как можно переменной j присваивать действие процедуры epcs_write_buffer ?
Это корректно?
Ведь в следующей строке этой же переменной j присваиватся результат действия процедуры epcs_read_buffer.

Посмотрите как обьявляется функция epcs_write_buffer:
Код
alt_32 epcs_write_buffer(alt_u32 base, int offset, const alt_u8* src_addr,
                         int length, alt_u32 four_bytes_mode)

Она возвращает тип alt_32, так что всё правильно.
FLTI
Тогда в чём в итоге была проблема?
Я сейчас похожую штуку буду применять, поэтому интересно.

Не могу даже поиском по сайту Альтеры найти описание на epcs_commands.h чтобы понять - как это функция epcs_write_buffer возвращает тип alt_32 и что это вообще за тип alt_32.
vadimuzzz
ищите в: ip/altera/sopc_builder_ip/

epcs_commands.c:
CODE

...
alt_32 epcs_read_buffer(alt_u32 base, int offset, alt_u8 *dest_addr, int length)
{
alt_u8 read_command[4];

read_command[0] = epcs_read;
read_command[1] = (offset >> 16) & 0xFF;
read_command[2] = (offset >> 8) & 0xFF;
read_command[3] = offset & 0xFF;

#if 0
/* If a write is in progress, fail. */
if (epcs_test_wip(base))
return 0;
#endif
/* I don't know why this is necessary, since I call await-wip after
* all writing commands.
*/
epcs_await_wip_released(base);

alt_avalon_spi_command(
base,
0,
sizeof(read_command) / sizeof(*read_command),
read_command,
length,
(alt_u8*)dest_addr,
0
);

return length;
...
}

alt_types.h:
Код
...
typedef unsigned long alt_u32;
...
FLTI
Если использовать драйвер epcs_commands.h, то надо ли делать какую-нибудь инициализацию или сразу можно читать командой epcs_read_buffer ?
vadimuzzz
Цитата(FLTI @ Apr 24 2015, 12:19) *
Если использовать драйвер epcs_commands.h, то надо ли делать какую-нибудь инициализацию или сразу можно читать командой epcs_read_buffer ?

можно сразу читать
FLTI
По мотивам кодов в данной теме составил такой код:
Код
            unsigned int i;
             alt_u8 data[16];
    
             // адрес EPCS контроллера
             const alt_u32 EPCS_ADDR = EPCS_FLASH_CONTROLLER_0_BASE + EPCS_FLASH_CONTROLLER_0_REGISTER_OFFSET;
             // смещение параметров модуля в EPCS - 0 байт
             const alt_u32 EPCS_PARAMS_OFFSET = 0;
             // режим байтов для EPCS
             const alt_u32 EPCS_BYTE_MODE = 0;

             epcs_read_buffer(EPCS_ADDR, EPCS_PARAMS_OFFSET, &data, 16, EPCS_BYTE_MODE);

      for(i=0;i<16;i++)
      {
             IOWR_8DIRECT(ONCHIP_MEMORY2_0_BASE, 16+i, data[i]);
      }


Вроде всё нормально, но компилятор в Eclipse выдаёт предупреждение:
warning: passing argument 3 of 'epcs_read_buffer' from incompatible pointer type [enabled by default]
Что бы это значило?
В EPCS записан .jic с таким .map файлом:
BLOCK START ADDRESS END ADDRESS
Page_0 0x00000000 0x0006AD41
ПЛИС Cyclone 4 GX с этого файла нормально стартует, правильно грузится прошивка и правильно выполняется программа НИОСа.

Судя по всему если я буду читать эту EPCS с нулевого смещения , то первые три байта должны быть 0x4a 0x49 0x43, что соответствует кодам букв JIC ?
Потому что эти 3 буквы я вижу с нулевого смещения в .jic файле если посмотреть его в HEX Editor.
А чтение EPCS с нулевого смещения вышеприведённым кодом даёт первые 16 байт равные 0xFF.
По более старшим адресам ( читаю окнами по 16 байт ) в EPCS лежат уже не 0xFF, но прочитанные значения не находятся в .jic файле если поискать их с помощью HEX Editor.


UPD
Сделал запись в область со смещением , а потом чтение, всё верно получается - прочитанное совпало с записанным.


Код
            int i;
            int j;
            alt_u8 data_A[16];
            alt_u8 data_B[16];
    
            // адрес EPCS контроллера
            const alt_u32 EPCS_ADDR = EPCS_FLASH_CONTROLLER_0_BASE + EPCS_FLASH_CONTROLLER_0_REGISTER_OFFSET;
            // нулевое смещение параметров модуля в EPCS
            const alt_u32 EPCS_PARAMS_OFFSET = 16*65536;
            // режим байтов для EPCS
            const alt_u32 EPCS_BYTE_MODE = 0;


for(i=0;i<16;i++)
{
data_A[i]=i;
}
epcs_write_enable(EPCS_ADDR);
epcs_sector_erase(EPCS_ADDR, EPCS_PARAMS_OFFSET, EPCS_BYTE_MODE);
epcs_write_buffer(EPCS_ADDR, EPCS_PARAMS_OFFSET, &data_A, 16, EPCS_BYTE_MODE);

epcs_read_buffer(EPCS_ADDR, EPCS_PARAMS_OFFSET, &data_B, 16, EPCS_BYTE_MODE);
for(j=0;j<16;j++)
{
IOWR_8DIRECT(ONCHIP_MEMORY2_0_BASE, 16+j, data_B[j]);
}


Почему же прочитанный из EPCS .jic не совпадает с .jic файлом?
Stewart Little
Цитата(FLTI @ Apr 24 2015, 16:08) *
Почему же прочитанный из EPCS .jic не совпадает с .jic файлом?

В паралельной ветке уважаемый krux объяснил Вам, почему. Потому, что jic в EPCS не записывается!
Jic - это комбинация SFL и sof-файла (ну, может быть дополнен еще hex'ом, если для Nios'a приложение).
Так что рекомендую разобраться с тем, что какой файл делает, и как именно.
FLTI
Мне нужно исходный .jic файл, записанный в EPCS по адресу 0x00 заменить на другой .jic файл командами epcs_write_buffer ( из драйвера epcs_commands.h ).
Как это сделать?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.