[[ADC_software-hardware]]


Про настройку linux для работы с АЦП: [[АЦП E-502]]

Описание работы с BF: [[x502_low_level.pdf]]
# how-to
## load firmware to Blackfin DSP
При использовании штатной библиотеки x502api для загрузки прошивки с
компьютера достаточно установить связь с устройством и вызвать функцию
X502_BfLoadFirmware(), которая загружает прошивку, проверяет ее работу
с помощью команды L502_BF_CMD_CODE_GET_PARAM с параметром
L502_BF_PARAM_FIRM_VERSION (подробнее смотри раздел Командный ин-
терфейс между ПК и сигнальным процессором), передает прошивке необходимую
информацию о модуле, после чего переводит модуль в режим работы с DSP.

Загружаем .ldr


## setup ADC sampling etc. Настройка параметров сбора данных
Как и для API верхнего уровня, прошивка BlackFin может устанавливать парамет-
ры сбора данных только в момент, когда не запущен синхронный ввод-вывод. В штат-
ной прошивке, как и в API верхнего уровня, сперва задаются все параметры, после
чего вызывается специальная функция (configure()), которая их непосредственно запи-
сывает в регистры ПЛИС. Сами параметры хранятся в структуре g_set. Они могут
быть заданы как командами из программы ПК при вызове X502_Configure(), так и
изменены внутри самой прошивкой. Для изменения можно как напрямую изменять по-
ля структуры g_set, так и использовать функции из l502_param.h (params_set_lch(),
params_set_adc_freq_div() и т.д.), которые дополнительно проверяют значения пара-
метров. Сами параметры аналогичны используемым в API верхнего уровня (правда
частоты сбора необходимо устанавливать вручную с помощью делителей и межкадро-
вой задержки).
После изменения параметров из прошивки необходимо перед запуском сбора не за-
быть вызвать configure().
## алгоритм работы:
см 5.7 Командный интерфейс между ПК и сигнальным
процессором
1. записываем команду (по номеру), аргументы.
2. DSP загружает её в память, выставляет флаг "работаем"
3. DSP вызывает соответствующую функцию
4. ф-ция отрабатывает
# Realisation
Задача: 
	1. Запуск, настройка АЦП
	2. Получение данных от АЦП
	3. рассчет FFT для одного ЛЧМ. Плата генератора должна подавать сигнал о том, что ЛЧМ в процессе, чтобы разделять данные для разных ЛЧМ
	4. выдача результата на ПК
## Решение:
### Программа на PC
Функционал:
- загружает прошивку в BlackFin (X502_BfLoadFirmware())
- настраивает АЦП 
- отправляет в BF команду на запуск работы
- принимает данные от BF
- отправляет BF пользовательские команды для управления (задать константы, управление обработкой и т.п.)
### BlackFin software
Этапы создания ПО:
- [x] прием чисел от ПК, умножение на константу (задаваемую отдельной функцией)
- [x] прием данных от АЦП, пересылка на ПК
- [ ] FFT обработка данных АЦП, пересыл на ПК



Если l502_cmd_done() вызывается дважды -- на ПК посылабтся данные последнего вызова. По крайней мере, если вызовы происходят подряд


## hints:
Если l502_cmd_done() вызывается дважды -- на ПК посылабтся данные последнего вызова. По крайней мере, если вызовы происходят подряд

### Про потоки данных и HostDMA:
HDMA должен конфигурироваться с компа.
Если конфигурировать с BlackFin, то настройки в ПЛИС будут изменены, всё сконфигурируется, но ПК и драйвер об этом знать не будут. Решение:
Вызывать с ПК:
1. X502_StreamsEnable()
2. X502_StreamsStart()
непосредственно прием:
3. X502_GetRecvReadyCount()
4. X502_Recv()



Данные АЦП попадают в BF по интерфейсу SPORT0:
![[Pasted image 20250627192138.png]]



Реализация чтения данных АЦП:
функция usr_in_proc_data(): Функция вызывается каждый раз, когда обнаружены новые данные от АЦП/цифровых входов, пришедшие по SPORT0. By defalut -- просто отправляет данные по HDMA
Последовательность (предположительно): См главу 5.8 
1. задание параметров АЦП
2. задание L502_BF_PARAM_IN_STREAM_MODE = 0x100 / Режим работы потока на ввод /
3. разрешение потоков IO BF (L502_BF_CMD_CODE_STREAM_EN)
4. запуск потоков (L502_BF_CMD_CODE_STREAM_START)
5. запуск DSP в режиме потоков L502_BF_MODE_STREAM
См главу 5.8 lowlevel_guide

## Формат данных в потоке на ввод и на вывод
Существует только один поток на ввод и один на вывод. Данные в потоке передаются в виде 32-битных слов. При этом в 32-битном слове, помимо самих данных закодировано и что это за данные (АЦП или DIN). Определить, что за данные, можно по старшему байту принятого слова. 
Ниже приведена таблица для определения какому типу данных принадлежит принятое слово из потока ввода:


| Биты 31-24 | hex          | Значение                 |
| ---------- | ------------ | ------------------------ |
| 1xxxxxxx   | 0x80 -- 0xFF | Данные от АЦП            |
| 00000000   | 0x00         | Данные с цифровых входов |
| 00000001   | 0x01         | Сообщения (от BF в ПК)   |
| 001xxxxx   | 0x20 -- 0x3F | Резерв                   |
| 01xxxxxx   | 0x40 -- 0x7F | Пользовательские данные  |

Непосредственно от ПЛИС по SPORT0 приходят только данные от АЦП и цифровых входов. Сообщения могут генерироваться в прошивке BlackFin для уведомления программы ПК о событиях. Сейчас используется только одно сообщение — сообщение о переполнении буфера. Штатная прошивка передает это сообщение при переполнении буфера SPORT0 на прием. При работе в режиме без DSP это сообщение генерируется аппаратно ПЛИС при переполнении внутреннего буфера DMA на ввод. Данные от АЦП приходят в виде расширенного 24-битного формата в дополнительном коде, так как к ним уже аппаратно применены калибровочные коэффициенты. Код L502_ADC_SCALE_CODE_MAX соответствует напряжению равному границе данного диапазона (например, +10В, +2В и т.д.).

**Данные от АЦП приходят в следующем формате:**

| 31-24    | 23-0                     |
| -------- | ------------------------ |
| 11mmcccc | dddddddddddddddddddddddd |
- d — 24-битный скорректированный дополнительный код АЦП.
- с — номер канал: “0” — 1-ый или 17-ый, “15” — 16-ый или 32-ой канал (в зависимости от режима).
- m — режим измерения:
	- 0 — дифференциальный
	- 1 — первые 16 каналов с общей землей
	- 2 — вторые 16 с общей землей
	- 3 — собственный ноль


**С цифровых линий данные приходят в следующем формате:**


| 31-24    | 23-16    | 15-8     | 7-0      |
| -------- | -------- | -------- | -------- |
| 00000000 | 000000ss | dddddddd | dddddddd |

- d — значения цифровых линий
- s — значение линий DI_SYN1 (16-ый бит) и DI_SYN2 (17-ый бит)

Для слов потока на вывод схожим образом по старшем битам определяется, для
чего предназначены данные:






## random from docs:

Размещение неинициализуемоего массива (буфера). подключать файл надо перед каждым объявлением.
`#include ‘‘l502_sdram_noinit.h’’
`static volatile uint32_t f_sport_in_buf[L502_SPORT_IN_BUF_SIZE];



### HostDMA
Запись и чтение по HostDMA всегда осуществляются блоками, кратными
восьми 32-битным словам (32 байта). Таким образом при записи массива данных разме-ром, некратным размеру блока, будет испорчена часть данных за записываемой частью до границы, кратной 32-м байтам

Для прямого доступа к памяти со стороны ПК в библиотеке l502api введены функ-
ции X502_BfMemRead() и X502_BfMemWrite(). При этом реально обмен осуществляется
блоками с максимальным размером 128 32-битных слов (512 байт), т.е. при вызове функ-ции с большим размером, массив данных будет разбит на несколько блоков, которые будут последовательно записаны/прочитаны. **надо следить за использованием, для исключения чтения недообработанных данных**

Изменение состояния этих выходов (toggle) при нулевом значении на выходах PF14 или PF15 является признаком, что в памяти BlackFin есть готовый новый блок для передачи или есть место для приема очередного блока на вывод. При этом **можно сообщить о готовности нового блока до завершения предыдущего**, так как ПЛИС сохраняет количество готовых, но не завершенных запросов на обмен. Всего может быть до 31 (определено через L502_IN_HDMA_DESCR_CNT и 502_OUT_HDMA_DESCR_CNT) незавершенных запросов по каждому направлению.

**Для описания запросов на обмен используются дескрипторы**, которые хранятся в фиксированной области памяти BlackFin (g_state.hdma.in[] и g_state.hdma.out[]). Состав дескриптора описан типом t_hdma_stream_descr. После сброса автомата ПЛИС ножками PF14 и PF15, автомат ожидает дескриптор по фиксированным адресам: &g_state.in[0] (0xFF800020) для ввода и &g_state.out[0] (0xFF800420) для вывода. Адрес же каждого следующего дескриптора задается в предыдущем дескрипторе.
По **завершению** чтения или записи данных, соответствующих дескриптору, **ПЛИС**
**записывает обработанный дескриптор полностью обратно в память BlackFin** по адре-
сам &g_state.in_lb (0xFF800000) и &g_state.out_lb (0xFF800400), **меняя нек. поля**. Прошивка использует поле valid, чтобы узнать о завершении запроса.

#### Алгоритм передачи данных для потока ввода выглядит схожим образом:

- При запуске потока прошивка вызывает функцию hdma_send_start(), которая
устанавливает выход PF14 в 0 — разрешается поток на ввод
- При наличии блока данных на передачу необходимо вызвать hdma_send_req_start()
с указанием буфера с данными — функция заполняет дескриптор g_state.in[0] нужными значениями (full_size=size*2, xcnt=min(256, size*2), addr, valid=1, id) и изменяет состояние выхода PG5, чтобы сообщить ПЛИС о готовности нового запроса.
- ПЛИС по этому сигналу, когда будет свободна шина HostDMA, считывает де-
скриптор из g_state.in[0].
- При наличии места в памяти ПК на прием и свободной шине HostDMA идет чтение данных из памяти BlackFin, начиная с адреса g_state.in[0].addr, блоками размером не больше xcnt 16-битных слов с последующей записью в память ПК. 
- При передаче всех full_size слов записывается считанный до этого дескриптор с измененными полями full_size и addr по адресу &g_state.in_lb.
- По завершению этой записи в обработчике hdma_isr() прошивка определяет по g_state.in_lb.valid, что записан дескриптор, устанавливает g_state.in_lb.valid в 0, вычисляет обработанный размер и вызывает hdma_send_done(). hdma_send_done() реализовано в l502_user_process.c. 
- При передаче на вывод в обратно записанном дескрипторе full_size=0, что соответствует полностью обработанному дескриптору.
- По мере необходимости добавляются новые дескрипторы через  dma_send_req_start(). 
- Дожидаться завершения предыдущего не обязательно — задания на передачу данных ставятся в очередь. Только нужно проверить, что есть место в очереди через hdma_send_req_rdy().
- При завершении потокового ввода вызывается hdma_send_stop(), которая устанавливает PF14 в 1, что приводит к сбросу автомата приема потока на ввод по HostDMA в ПЛИС.

### SPORT0 (5.9)


В отличии от остальных интерфейсов для приема-передачи потоков данных, где обмен осуществляется через дескрипторы и может быть приостановлен, пока новый дескриптор не будет поставлен в очередь, прием синхронных данных от АЦП/DIN всегда осуществляется непрерывно со скоростью ввода этих данных. Прием осуществляется 32-битными словами. При этом каждое 32-битное слово передается как два 16-битных, передаваемых параллельно — одно по первичному каналу SPORT0, второе — по вторичному. При приеме используется внешний сигнал начала кадра (RFS), который генерирует ПЛИС каждый раз при наличии нового принятого отсчета АЦП или DIN. 
Сигнал RFS должен быть явно разрешен с помощью установки бита BF_RFS_EN регистра OUTSWAP_BFCTL. Для ра.
приема
Прием
используется
данных
третий
происходит
канал
постоянно
DMA
в
BlackFin
буфер
в
режимеавтобуфе-
f_sport_in_bufразмером
L502_SPORT_IN_BUF_SIZE. Сам буфер разделен на блоки, размер каждого из
которых
равен
шагу
прерывания.
Этот
шаг
может
быть
установлен
с
помощью
функции sport_in_set_step_size(). В штатной прошивке установка этого параметра
осуществляется
с
ПК
через
команду
L502_BF_CMD_CODE_SET_PARAM
с
параметром L502_BF_PARAM_IN_STEP_SIZE, но ничего не мешает изменять его
из самой прошивки пока синхронные потоки не запущены.
Для реализации приема данных с указанным шагом используется 2D режим DMA,
где размер по X равен размеру шага (умноженному на 2, т.к. используется 16-битный
77режим DMA), а по Y - количеству шагов, которое помещается в буфере на прием (долж-
но быть не меньше 3). Таким образом, если размер буфера на прием не кратен шагу,
то реально используется не весь буфер, а наибольший размер кратный шагу, но не
превышающий размер буфера.
После приема данных, размер которых соответствует шагу прерывания, будет вы-
зван обработчик isr_sport_dma_rx(), в котором обновляется размер принятых данных
в буфере и проверяется переполнение. Т.к. прерывание возникает при завершении при-
ема блока данных, когда уже начат прием следующего блока, то, чтобы не допустить
порчи данных из-за переполнения буфера, необходимо, чтобы в момент прерывания
было свободно для приема как минимум два блока. В противном случае, если к следу-
ющему прерыванию хотя бы еще один блок не освободится, то о переполнении прошивка
узнает только в момент, когда часть буфера уже была повреждена (что может приве-
сти к тому, что будут обработаны испорченные данные). Таким образом, для надежного
приема данных, если в прерывании обнаруживается, что свободно меньше двух блоков,
то это считается переполнением.
По переполнению останавливается прием по интерфейсу SPORT0 и взводится спе-
циальный флаг. После этого обрабатываются все принятые, но необработанные данные
в буфере, после чего в ПК посылается слово о том, что в данном месте было перепол-
нение.
Управление приемом по SPORT0 осуществляется из функций управления потока-
ми: при запуске синхронного ввода-вывода и разрешенных потоках на ввод выпол-
няется функция sport_rx_start(), которая настраивает DMA, сбрасывает указатели
в буфере на прием и разрешает прием по SPORT0. При останове синхронного ввода-
вывода или запрете всех потоков на ввод выполняется останов приема по SPORT0 через
sport_rx_stop().



# preparations
## установка CrossCode Embedded Studio
- source: https://www.analog.com/en/resources/evaluation-hardware-and-software/embedded-development-software/adswt-cces.html#software-relatedsoftware
- instuctions: https://download.analog.com/tools/CrossCoreEmbeddedStudio/Releases/Release_2.12.1/CrossCoreEmbeddedStudio_Installation_Guide.pdf, local: [[CrossCoreEmbeddedStudio_Installation_Guide.pdf]]

## альтернатива: установка blfn-elf-gcc
Исходники: git clone https://github.com/deanm1278/blackfin-plus-gnu.git
Сборка:
	cd blackfin-plus-gnu/gcc
	./contrib/download_prerequisites
	cd ../buildscript/
	./build.sh
Однако, возникают ошибки компиляции.
ChatGPT:

	Ошибка компиляции, с которой вы столкнулись при сборке кросс-компилятора для Blackfin, связана с изменениями в компиляторе GCC, начиная с версии 8. В частности, GCC стал более строго проверять приведения типов между несовместимыми указателями на функции, что приводит к ошибкам при компиляции устаревших версий `binutils`, используемых в проекте `blackfin-plus-gnu`.
Решение:
	добавить
		export CFLAGS="-Wno-error=cast-function-type"
	    export CXXFLAGS="-Wno-error=cast-function-type"
	В build.sh 



#### Сборка в chroot
Создание chroot в /srv/chroot:
`sudo debootstrap --variant=buildd --arch=amd64 focal /srv/chroot/focal-amd64 http://archive.ubuntu.com/ubuntu

mounts:
sudo mount --bind /proc /srv/chroot/focal-amd64/proc
sudo mount --bind /sys /srv/chroot/focal-amd64/sys
sudo mount --bind /dev /srv/chroot/focal-amd64/dev
sudo cp /etc/resolv.conf /srv/chroot/focal-amd64/etc/

sudo mount --bind /sharedfolder /srv/chroot/shared

вход в chroot:
sudo chroot /srv/chroot/focal-amd64 /bin/bash

#### Как войти в chroot после перезагрузки

1. **Смонтируйте нужные файловые системы**, если они ещё не примонтированы:
	sudo mount --bind /proc /srv/chroot/focal-amd64/proc
	sudo mount --bind /sys   /srv/chroot/focal-amd64/sys
	sudo mount --bind /dev   /srv/chroot/focal-amd64/dev
	sudo cp /etc/resolv.conf /srv/chroot/focal-amd64/etc/
- Это нужно для работоспособности среды и выхода в интернет. [geeksforgeeks.org+15wiki.ubuntu.com+15stackoverflow.com+15](https://wiki.ubuntu.com/DebootstrapChroot?utm_source=chatgpt.com)
    
- **Войдите в chroot**:
## альтернатива: official old toolchain
https://sourceforge.net/projects/adi-toolchain/files/2014R1/2014R1-RC2/x86_64/
Скачали в Blackfin/toolchain_off
прописали в PATH:
`export PATH=/home/feda/MIPT/RadioPhotonic_Subserface_radar/BlackFin/toolchain_off/bfin-elf/bin:$PATH`
Работает!
