Реалити-шоу «КБ13 и АЦП». День 1.

Намигавшись диодами (инсталляция «я и диод») в течение получаса, мы получили полное моральное право перейти к отработке действительно нужных вещей.

Случайным образом из кучи задач была выбрана одна — заполнение и чтение FIFO буферов, то есть запись и чтение внешней SDRAM-памяти.

Памяти у нас в распоряжении оказалось 8 МБ (ровно по 512 КБ на каждый канал), sdram, согласно даташиту поддерживает запись как слов (32 бита), так и полуслов (16 бит) и четверть-слов (8 бит).

АЦП при чтении возвращает с каждого канала signed short значение оцифрованного напряжения. Т.е. 16 бит. Значит, если мы хотим прожигать в память данные длинной в слово, сбрасывать буфера нужно каждые два чтения.

Простая тестовая программа суть должна делать следующее — инициализация памяти, подсчет количества слов, которые мы имеем в памяти, два чтения ацп с записью результатов в буфер типа long (соответсвующий слову памяти), сброс буфера в память, чтение из памяти и сравнение значений — все ли правильно.

Для простоты будем писать все каналы подряд, а не в отдельные буферы — т.е. не будем смещаться на 512 КБ, когда пишем другой канал.

Отбрасывая функции инициализации железа, установки прерываний и т.п., на скорую руку вышла вот такая main():

signed short adc_buffer[16];
volatile unsigned long *sdram = SDRAM;

int main(void)
{
  int i;
  signed long adc[16],adc_read[16]; // буфера для обмена с памятью
  signed short read1[16],read2[16],mem1[16],mem2[16]; // буфера со значениями с АЦП

  init();

  memset(adc,0,16*sizeof(signed long));
  memset(adc_read,0,16*sizeof(signed long));
  memset(read1,0,16*sizeof(signed short));
  memset(read2,0,16*sizeof(signed short));
  memset(mem1,0,16*sizeof(signed short));
  memset(mem2,0,16*sizeof(signed short));

  // первое чтение
  ad7657_read(adc_buffer);
  memcpy(read1,adc_buffer,16*sizeof(signed short) );
  memcpy(adc,adc_buffer,16*sizeof(signed short) );

  // второе чтение
  ad7657_read(adc_buffer);
  memcpy(read2,adc_buffer,16*sizeof(signed short) );
  memcpy(&adc[8],adc_buffer,16*sizeof(signed short) );

  // сбрасываем в память буфер из 16 слов
  for(i=0;i<16;i++){
	  sdram[i]=adc[i];
  }

  // пауза...
  for(i=0;i<500;i++){
	  ;
  }

  // считываем 16 слов
  for(i=0;i<16;i++){
	  adc_read[i]=sdram[i];
   }

  // разбираем считанные слова
  memcpy( &mem1, adc_read, 16*sizeof(signed short) );
  memcpy( &mem2, &adc_read[8], 16*sizeof(signed short) );

  while(1);
}

И, что характерно, значения в буферах до записи в память и после чтения из нее - не сходятся.

Ошибка оказалась элементарной - буфер лонгов нужно было объявить unsigned. После этого записанные и считанные буферы стали сходиться.
Также внесем пару строчек изменений, чтобы буфера каналов распределялись по памяти правильно - у каждого было по 512 КБ. Для этого нужно изменить порядок записи результатов измерений во временные буфера. А так же посчитать в словах смещение каждого буфера относительно предыдущего - 512КБ/32б = 131072.

#define OFFSET_WORD 131072
signed short adc_buffer[16];
volatile unsigned long *sdram = SDRAM;

int main(void)
{
  int i;
  unsigned long adc[16]; // буфер для обмена с памятью

  init();

  memset( adc,0,16*sizeof(signed long) );

  // первое чтение
  ad7657_read(adc_buffer);
  for( i=0; i<16; i++ ){
           memcpy( &adc[i], &adc_buffer[i], sizeof(signed short) );
  }

  // второе чтение
  ad7657_read(adc_buffer);
  for( i=0; i<16; i++ ){
           memcpy( &adc[i]+sizeof(signed short), &adc_buffer[i], sizeof(signed short) );
  }

  // сбрасываем в память буфер из 16 слов
  for( i=0; i<16; i++ ){
	  sdram[i*OFFSET_WORD]=adc[i];
  }

  while(1);
}

В результате выполнения этой программы получаем для каждого канала результаты двух чтений, расположенные на нужном месте - с 512КБ смещением относительно начала предыдущего буфера.

Мораль дня - если нужно использовать переменную в качестве буфера, лучше сразу объявить ее как беззнаковую.

Похожий бред:

Реалити-шоу «КБ13 и АЦП». День 1.: 1 комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Protected by WP Anti Spam