git init of an empty project
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
/***************************************************************************//**
|
||||
@addtogroup async_io
|
||||
@{
|
||||
@file l502_async.c
|
||||
Ôàéë ñîäåðæèò ðåàëèçàöèþ ôóíêöèé äëÿ àñèíõðîííîãî ââîäà/âûâîäà
|
||||
(ïîêà òîëüêî âûâîäà)
|
||||
******************************************************************************/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "l502_cmd.h"
|
||||
#include "l502_global.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_defs.h"
|
||||
#include "l502_async.h"
|
||||
#include "l502_fpga_regs.h"
|
||||
|
||||
|
||||
|
||||
|
||||
void async_dac_out(uint8_t ch, int32_t val) {
|
||||
val &= 0xFFFF;
|
||||
if (ch==L502_DAC_CH1) {
|
||||
val |= L502_STREAM_OUT_WORD_TYPE_DAC1;
|
||||
} else {
|
||||
val |= L502_STREAM_OUT_WORD_TYPE_DAC2;
|
||||
}
|
||||
fpga_reg_write(L502_REGS_IOHARD_ASYNC_OUT, val);
|
||||
}
|
||||
|
||||
|
||||
void async_dout(uint32_t val, uint32_t msk) {
|
||||
static uint32_t last_out = L502_DIGOUT_WORD_DIS_H | L502_DIGOUT_WORD_DIS_L;
|
||||
if (msk != 0) {
|
||||
val &= ~msk;
|
||||
val |= last_out & msk;
|
||||
}
|
||||
val &= 0xFFFF;
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_ASYNC_OUT, val);
|
||||
last_out = val;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,46 @@
|
||||
/** @defgroup async_io Асинхронный ввод-вывод */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup async_io
|
||||
@{
|
||||
@file l502_async.h
|
||||
|
||||
Файл содержит описания функций асинхронного ввода-вывода
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L502_ASYNC_H_
|
||||
#define L502_ASYNC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Первый канал ЦАП при выводе через async_dac_out() */
|
||||
#define L502_DAC_CH1 0
|
||||
/** Второй канал ЦАП при выводе через async_dac_out() */
|
||||
#define L502_DAC_CH2 1
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Асинхронный вывод на один из каналов ЦАП
|
||||
|
||||
Функция выполняет асинхронный вывод кода на ЦАП
|
||||
@param[in] ch Канал ЦАП (#L502_DAC_CH1 или #L502_DAC_CH2)
|
||||
@param[in] val Код ЦАП (действительны только младшие 16 бит)
|
||||
******************************************************************************/
|
||||
void async_dac_out(uint8_t ch, int32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Асинхронный вывод на цифровые линии
|
||||
|
||||
Функция выполняет асинхронный вывод кода на цифровые линии с возможностью указать
|
||||
линии, которые не должны изменяться
|
||||
@param[in] val биты 0-15 - значения линий на вывод + возможно перевести
|
||||
половину портов в 3-е состояние с помощью флагов из
|
||||
#t_l502_digout_word_flags
|
||||
@param[in] msk Если в маске установлены некоторые биты, то соответствующие
|
||||
биты из val не влияют, а сохраняются предыдущие значения
|
||||
******************************************************************************/
|
||||
void async_dout(uint32_t val, uint32_t msk);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,167 @@
|
||||
/*********************************************************************//**
|
||||
@addtogroup cmd_process
|
||||
@{
|
||||
@file l502_bf_cmd_defs.h Файл содержит определения,
|
||||
которые используются для передачи команд от ПК в DSP
|
||||
(определения команд, их параметров, результатов выполнения)
|
||||
@date 28.03.2012
|
||||
@author Borisov Alexey <borisov@lcard.ru>
|
||||
*************************************************************************/
|
||||
#ifndef L502_BF_CMD_DEFS_H_
|
||||
#define L502_BF_CMD_DEFS_H_
|
||||
|
||||
/** Максимальный размер данных, передавемых с командой в 32-битных словах */
|
||||
#define L502_BF_CMD_DATA_SIZE_MAX (1024)
|
||||
|
||||
|
||||
|
||||
/** Статус команд управления сигнальным процессором */
|
||||
typedef enum {
|
||||
L502_BF_CMD_STATUS_IDLE = 0x0, /**< Начальное состояние (команда вообщен не выполнялась) */
|
||||
L502_BF_CMD_STATUS_REQ = 0x5A01, /**< Передан запрос на обработку команды от ПК*/
|
||||
L502_BF_CMD_STATUS_PROGRESS = 0x5A02, /**< Сигнальный процессор начал обработку команды */
|
||||
L502_BF_CMD_STATUS_DONE = 0x5A03 /**< Команда выполнена. Результат выполнения в поле ret_code */
|
||||
} t_l502_bf_cmd_status;
|
||||
|
||||
|
||||
/** Коды команд управления сигнальным процессором */
|
||||
typedef enum {
|
||||
L502_BF_CMD_CODE_TEST = 0x01, /**< Запуск теста (параметр определяет тип теста) */
|
||||
L502_BF_CMD_CODE_SET_PARAM = 0x02, /**< Установить параметр (код параметра в поле param) */
|
||||
L502_BF_CMD_CODE_GET_PARAM = 0x03, /**< Прочитать текущее значение параметра */
|
||||
L502_BF_CMD_CODE_CONFIGURE = 0x04, /**< Сконфигурировать модуль в соответствии с ранее установленными параметрами */
|
||||
L502_BF_CMD_CODE_STREAM_EN = 0x05, /**< Разрешение потоков ввода/вывода */
|
||||
L502_BF_CMD_CODE_STREAM_DIS = 0x06, /**< Запрещение потоков ввода/вывода */
|
||||
L502_BF_CMD_CODE_STREAM_START = 0x07, /**< Запуск потоков ввода/вывода */
|
||||
L502_BF_CMD_CODE_STREAM_STOP = 0x08, /**< Останов потоков ввода/вывода */
|
||||
L502_BF_CMD_CODE_PRELOAD = 0x09, /**< Предзагрузка данных на ЦАП */
|
||||
L502_BF_CMD_CODE_ASYNC_OUT = 0x10, /**< Асинхронный вывод (куда - зависит от параметра) */
|
||||
L502_BF_CMD_CODE_ASYNC_DIG_IN = 0x11, /**< Асинхронный ввод с цифровых линий */
|
||||
L502_BF_CMD_CODE_ADC_GET_FRAME = 0x12, /**< Асинхронный ввод карда АЦП */
|
||||
L502_BF_CMD_CODE_FPGA_REG_WR = 0x13, /**< Запись в регистр FPGA (param --- адрес регистра, data0 --- значение) */
|
||||
L502_BF_CMD_CODE_FPGA_REG_RD = 0x14, /**< Чтение из регистра FPGA (param --- адрес регистра, ответ: resp0 --- значение) */
|
||||
L502_BF_CMD_CODE_GET_OUT_STATUS= 0x15, /**< Получение флагов статуса вывода */
|
||||
} t_l502_bf_cmd_code;
|
||||
|
||||
#define L502_BF_CMD_CODE_USER 0x8000U /**< Код, с которого начинаются пользовательские команды */
|
||||
|
||||
|
||||
|
||||
/** @brief Варианты тестов
|
||||
|
||||
Коды тестов, передающиеся в параметре команды #L502_BF_CMD_CODE_TEST */
|
||||
typedef enum {
|
||||
L502_BF_CMD_TEST_STOP = 0x00, /**< Останов выполняемого теста */
|
||||
L502_BF_CMD_TEST_GET_RESULT = 0x01, /**< Получение результата теста */
|
||||
L502_BF_CMD_TEST_ECHO = 0x10, /**< Тест эхо - возвращает те же данные что передавались */
|
||||
L502_BF_CMD_TEST_SPORT = 0x11, /**< Тест интерфейса SPORT в кольцевом режиме */
|
||||
L502_BF_CMD_TEST_SDRAM = 0x12, /**< Тест SDRAM памяти */
|
||||
L502_BF_CMD_TEST_SPI = 0x13 /**< Тест интерфейса SPI */
|
||||
} t_l502_bf_test_code;
|
||||
|
||||
|
||||
/** @brief Устанавливаемые параметры
|
||||
|
||||
Коды пареметров, устанавливаемых командой #L502_BF_CMD_CODE_SET_PARAM или
|
||||
получаемых с помщью команды #L502_BF_CMD_CODE_GET_PARAM */
|
||||
typedef enum {
|
||||
L502_BF_PARAM_FIRM_VERSION = 0x00, /**< Версия прошивки - 4 байта */
|
||||
L502_BF_PARAM_STREAM_MODE = 0x01, /**< Режим работы (запущен поток или нет) */
|
||||
L502_BF_PARAM_ENABLED_STREAMS = 0x02, /**< Какие потоки разрешены */
|
||||
L502_BF_PARAM_MODULE_INFO = 0x03, /**< Запись информации о модуле */
|
||||
L502_BF_PARAM_IN_BUF_SIZE = 0x10, /**< Размер буфера на преием */
|
||||
L502_BF_PARAM_CYCLE_BUF_SIZE = 0x11, /**< Размер буфера для записи циклического сигнала */
|
||||
L502_BF_PARAM_LCH_CNT = 0x20, /**< Количество логических каналов в таблице */
|
||||
L502_BF_PARAM_LCH = 0x21, /**< Параметры логического канала */
|
||||
L502_BF_PARAM_ADC_FREQ_DIV = 0x22, /**< Делитель частоты АЦП */
|
||||
L502_BF_PARAM_REF_FREQ_SRC = 0x23, /**< Выбор опорной частоты */
|
||||
L502_BF_PARAM_ADC_FRAME_DELAY = 0x24, /**< Значение межкадровой задержки */
|
||||
L502_BF_PARAM_SYNC_MODE = 0x25, /**< Режим синхронизации */
|
||||
L502_BF_PARAM_SYNC_START_MODE = 0x26, /**< Условие запуска синхронных потоков сбора данных */
|
||||
L502_BF_PARAM_ADC_COEF = 0x27, /**< Установка коэффициентов для заданного диапазона АЦП */
|
||||
L502_BF_PARAM_DAC_COEF = 0x28, /**< Установка коэффициентов для заданного канала ЦАП */
|
||||
L502_BF_PARAM_DIN_FREQ_DIV = 0x30, /**< Делитель частоты цифрового ввода */
|
||||
L502_BF_PARAM_DAC_FREQ_DIV = 0x31, /**< Делитель частоты вывода на ЦАП */
|
||||
L502_BF_PARAM_IN_STEP_SIZE = 0x32, /**< Шаг для обработки входных данных */
|
||||
L502_BF_PARAM_IN_STREAM_MODE = 0x100 /**< Режим работы потока на ввод */
|
||||
} t_l502_bf_params;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Тип асинхронного вывода
|
||||
|
||||
Код, задающий в параметре команды команды #L502_BF_CMD_CODE_ASYNC_OUT,
|
||||
куда должно выводится передаваемое значение */
|
||||
typedef enum {
|
||||
L502_BF_CMD_ASYNC_TYPE_DOUT = 0x0, /**< Вывод на цифровые линии */
|
||||
L502_BF_CMD_ASYNC_TYPE_DAC1 = 0x1, /**< Вывод на первый канал ЦАП */
|
||||
L502_BF_CMD_ASYNC_TYPE_DAC2 = 0x2 /**< Вывод на второй канал ЦАП */
|
||||
} t_l502_bf_cmd_async_type;
|
||||
|
||||
/** Коды завершения команд */
|
||||
typedef enum {
|
||||
L502_BF_ERR_SUCCESS = 0, /**< Команда выполнена успешно */
|
||||
L502_BF_ERR_FIRST_CODE = -512, /**< Код ошибки, с которого начинаются отсальные коды.
|
||||
Используется, чтобы разделить на верхнем уровне ошибки библиотеки и
|
||||
возвращенные сигнальным процессором */
|
||||
L502_BF_ERR_UNSUP_CMD = -512, /**< Неизвестный код команды */
|
||||
L502_BF_ERR_CMD_OVERRUN = -513, /**< Пришла команда до того, как была завершена предыдущая */
|
||||
L502_BF_ERR_INVALID_CMD_PARAMS = -514, /**< Неверное значение параметра команды */
|
||||
L502_BF_ERR_INSUF_CMD_DATA = -515, /**< Недостаточное кол-во данных передано с командой */
|
||||
L502_BF_ERR_STREAM_RUNNING = -516, /**< Команда не допустима при запущеном сборе, а сбор запущен */
|
||||
L502_BF_ERR_STREAM_STOPPED = -517, /**< Команда допустима только при запущеном сборе, а сбор остановлен */
|
||||
L502_BF_ERR_NO_TEST_IN_PROGR = -518, /**< Сейчас не выполняется никакого теста */
|
||||
L502_BF_ERR_TEST_VALUE = -519 /**< Считано неверное значение при выполнении теста */
|
||||
} t_l502_bf_err_code;
|
||||
|
||||
|
||||
/** Режим работы сигнального процессора */
|
||||
typedef enum {
|
||||
L502_BF_MODE_IDLE = 0, /**< Ждущий режим, поток не запущен */
|
||||
L502_BF_MODE_STREAM = 1, /**< Запущены потоки ввода-вывода */
|
||||
L502_BF_MODE_TEST = 2 /**< Тестовый режим */
|
||||
} t_l502_bf_mode;
|
||||
|
||||
/** Возможности, поддерживаемые прошивкой blackfin */
|
||||
typedef enum {
|
||||
L502_BF_FEATURE_FPGA_REG_ACCESS = 0x1, /**< Признак, что реализованы команды
|
||||
прямого доступа к регистрам FPGA */
|
||||
L502_BF_FEATURE_OUT_STATUS_FLAGS = 0x2 /**< Признак, что реализована команда
|
||||
#L502_BF_CMD_CODE_GET_OUT_STATUS */
|
||||
} t_l502_bf_features;
|
||||
|
||||
/** @brief Параметры команды
|
||||
|
||||
Структура описывает расположение полей в области памяти BlackFin, используемой
|
||||
для передачи команд между персональным компьютером и сигнальным процессором */
|
||||
typedef struct {
|
||||
uint16_t code; /**< Код команды из #t_l502_bf_cmd_code */
|
||||
uint16_t status; /**< Статус выполнения - в обработчике не изменяется */
|
||||
uint32_t param; /**< Параметр команды */
|
||||
int32_t result; /**< Код результата выполнения команды */
|
||||
uint32_t data_size; /**< Количество данных, переданных с командой или возвращенных с ответом в 32-битных словах */
|
||||
uint32_t data[L502_BF_CMD_DATA_SIZE_MAX]; /**< Данные, передаваемые с командой и/или в качестве результата */
|
||||
} t_l502_bf_cmd;
|
||||
|
||||
|
||||
/** @brief Результат выполнения теста
|
||||
|
||||
Структура описывает параметры выполняемого теста, возвращаемые в качестве
|
||||
данных на команду #L502_BF_CMD_CODE_TEST с параметром
|
||||
#L502_BF_CMD_TEST_GET_RESULT */
|
||||
typedef struct {
|
||||
uint32_t test; /**< Номер выполняемого теста */
|
||||
uint32_t run; /**< Признак, запущен ли сейчас тест */
|
||||
uint32_t stage; /**< Этап выполнения теста */
|
||||
uint32_t cntr; /**< Счетчик - сколько раз прошел тест */
|
||||
int32_t err; /**< Код ошибки выполнения теста */
|
||||
uint32_t last_addr; /**< Последний используемый адрес */
|
||||
uint32_t last_wr; /**< Последнее записанное значение */
|
||||
uint32_t last_rd; /**< Последнее считанное значение */
|
||||
} t_l502_bf_test_res;
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/** @file l502_cdefs.h
|
||||
Ôàéë îïðåäåëÿåò íàáîð ìàêðîñîâ äëÿ âûïîëíåíèÿ îïåðàöèé, çàâèñÿùèé îò
|
||||
êîìïèëÿòîðà (VisualDSP èëè GCC) */
|
||||
|
||||
#ifndef L502_CDEFS_H
|
||||
#define L502_CDEFS_H
|
||||
|
||||
/** Ìàêðîñ äëÿ ïîìåùåíèÿ ïåðåìåííîé èëè ôóíêöèè â îïðåäåëåííóþ ñåêöèþ */
|
||||
#ifdef __GNUC__
|
||||
#define SECTION(sect, member) member __attribute__((section(sect)))
|
||||
#else
|
||||
#define SECTION(sect, member) section(sect) member
|
||||
#endif
|
||||
|
||||
/** Ìàðîñ äëÿ ïîìåùåíèÿ ïåðåìåííîé â íåèíèöèàëèçèðóåìóþ îáëàñòü SDRAM */
|
||||
#ifdef __GNUC__
|
||||
#define MEM_SDRAM_NOINIT(variable) SECTION(".sdram_noinit", variable)
|
||||
#else
|
||||
#define MEM_SDRAM_NOINIT(variable) section("sdram_noinit", NO_INIT) variable
|
||||
#endif
|
||||
|
||||
/** Ìàêðîñ äëÿ îïèñàíèÿ îáðàáîò÷èêà ïðåðûâàíèé */
|
||||
#ifdef __GNUC__
|
||||
#define ISR(handler) __attribute__((interrupt_handler,nesting)) void handler(void)
|
||||
#else
|
||||
#define ISR(handler) EX_INTERRUPT_HANDLER(handler)
|
||||
#endif
|
||||
|
||||
/** Ìàêðîñ äëÿ ðåãèñòðàöèè îáðàáîò÷èêà ïðåðûâàíèé */
|
||||
#ifdef __GNUC__
|
||||
#define REGISTER_ISR(ivg, isr) do { \
|
||||
int i=0; \
|
||||
ssync(); \
|
||||
*pEVT##ivg = isr; \
|
||||
ssync(); \
|
||||
asm volatile ("cli %0; bitset (%0, %1); sti %0; csync;": "+d"(i) : "i"(ivg)); \
|
||||
} while(0)
|
||||
#else
|
||||
#define REGISTER_ISR(ivg, isr) register_handler(ik_ivg##ivg, isr)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // L502_CDEFS_H
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
/***************************************************************************//**
|
||||
@addtogroup cmd_process
|
||||
@{
|
||||
@file l502_cmd.c
|
||||
Ôàéë ñîäåðæèò ëîãèêó îáðàáîòêè êîìàíä îò ÏÊ, ïåðåäàííûõ ÷åðåç
|
||||
HostDMA â BlackFin.
|
||||
Äëÿ êàæäîãî êîäà êîìàíäû â òàáëèöå f_cmd_tbl çàäàíà ôóíêöèÿ äëÿ
|
||||
îáðàáîòêè êîìàíäû. Åñëè â òàáëèöå êîä êîìàíäû íå íàéäåí,
|
||||
òî âîçâðàùàåòñÿ îøèáêà. Äëÿ ïîëüçîâàòåëüñêèõ êîìàíä
|
||||
âñåãäà âûçûâàåòñÿ usr_cmd_process().
|
||||
*******************************************************************************/
|
||||
|
||||
#include "l502_global.h"
|
||||
#include "l502_cmd.h"
|
||||
#include "l502_stream.h"
|
||||
#include "l502_params.h"
|
||||
#include "l502_user_process.h"
|
||||
#include "l502_async.h"
|
||||
#include "l502_sport_tx.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <cdefBF523.h>
|
||||
#include <sys/exception.h>
|
||||
#include <ccblkfn.h>
|
||||
#include "l502_fpga.h"
|
||||
|
||||
|
||||
|
||||
extern void l502_cmd_test(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_set_param(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_get_param(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_config(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_streams_start(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_stream_stop(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_preload(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_stream_enable(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_stream_disable(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_async_out(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_fpga_reg_wr(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_fpga_reg_rd(t_l502_bf_cmd *cmd);
|
||||
static void f_cmd_get_out_status(t_l502_bf_cmd *cmd);
|
||||
|
||||
|
||||
/* Òèï, îïèñûâàþùèé ôóíêöèþ îáðàáîòêè êîíêðåòíîé êîìàíäû */
|
||||
typedef void (*t_cmd_func)(t_l502_bf_cmd* cmd);
|
||||
|
||||
static const uint32_t f_regaddr_k[L502_ADC_RANGE_CNT] = {L502_REGS_IOARITH_K10,
|
||||
L502_REGS_IOARITH_K5,
|
||||
L502_REGS_IOARITH_K2,
|
||||
L502_REGS_IOARITH_K1,
|
||||
L502_REGS_IOARITH_K05,
|
||||
L502_REGS_IOARITH_K02};
|
||||
|
||||
static const uint32_t f_regaddr_offs[L502_ADC_RANGE_CNT] = {L502_REGS_IOARITH_B10,
|
||||
L502_REGS_IOARITH_B5,
|
||||
L502_REGS_IOARITH_B2,
|
||||
L502_REGS_IOARITH_B1,
|
||||
L502_REGS_IOARITH_B05,
|
||||
L502_REGS_IOARITH_B02};
|
||||
|
||||
|
||||
|
||||
static volatile uint8_t f_cmd_req=0;
|
||||
/* òàáëèöà ñ ñîîòâåòñòâèåì êîäîâ êîìàíä è ôóíêöèé äëÿ èõ âûïîëíåíèÿ */
|
||||
static const struct {
|
||||
uint32_t cmd_code;
|
||||
t_cmd_func start;
|
||||
} f_cmd_tbl[] = {
|
||||
{L502_BF_CMD_CODE_TEST, l502_cmd_test},
|
||||
{L502_BF_CMD_CODE_SET_PARAM, f_cmd_set_param},
|
||||
{L502_BF_CMD_CODE_GET_PARAM, f_cmd_get_param},
|
||||
{L502_BF_CMD_CODE_CONFIGURE, f_cmd_config},
|
||||
{L502_BF_CMD_CODE_STREAM_START, f_cmd_streams_start},
|
||||
{L502_BF_CMD_CODE_STREAM_STOP , f_cmd_stream_stop},
|
||||
{L502_BF_CMD_CODE_PRELOAD, f_cmd_preload},
|
||||
{L502_BF_CMD_CODE_STREAM_EN, f_cmd_stream_enable},
|
||||
{L502_BF_CMD_CODE_STREAM_DIS, f_cmd_stream_disable},
|
||||
{L502_BF_CMD_CODE_ASYNC_OUT, f_cmd_async_out},
|
||||
{L502_BF_CMD_CODE_FPGA_REG_WR, f_cmd_fpga_reg_wr},
|
||||
{L502_BF_CMD_CODE_FPGA_REG_RD, f_cmd_fpga_reg_rd},
|
||||
{L502_BF_CMD_CODE_GET_OUT_STATUS, f_cmd_get_out_status},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void l502_cmd_done(int32_t result, uint32_t* data, uint32_t size) {
|
||||
g_state.cmd.result = result;
|
||||
g_state.cmd.data_size = size;
|
||||
if (size && (data!=g_state.cmd.data))
|
||||
memmove((void*)g_state.cmd.data, data, size*sizeof(data[0]));
|
||||
|
||||
g_state.cmd.status = L502_BF_CMD_STATUS_DONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void l502_cmd_start(t_l502_bf_cmd* cmd) {
|
||||
uint32_t i, fnd;
|
||||
|
||||
if (cmd->code & L502_BF_CMD_CODE_USER) {
|
||||
usr_cmd_process(cmd);
|
||||
} else {
|
||||
for (i=0, fnd=0; !fnd && (i < sizeof(f_cmd_tbl)/sizeof(f_cmd_tbl[0])); i++) {
|
||||
if (cmd->code == f_cmd_tbl[i].cmd_code) {
|
||||
fnd = 1;
|
||||
f_cmd_tbl[i].start(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fnd)
|
||||
l502_cmd_done(L502_BF_ERR_UNSUP_CMD, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void l502_cmd_check_req(void) {
|
||||
if (f_cmd_req == 1) {
|
||||
f_cmd_req=0;
|
||||
l502_cmd_start((void*)&g_state.cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void l502_cmd_set_req(void) {
|
||||
f_cmd_req = 1;
|
||||
g_state.cmd.status = L502_BF_CMD_STATUS_PROGRESS;
|
||||
}
|
||||
|
||||
static void f_cmd_streams_start(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(streams_start(), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_stream_stop(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(streams_stop(), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_config(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(configure(), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_preload(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(stream_out_preload(), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_stream_enable(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(stream_enable(cmd->param), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_stream_disable(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(stream_disable(cmd->param), NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_async_out(t_l502_bf_cmd *cmd) {
|
||||
int32_t err = 0;
|
||||
if (cmd->data_size < 1) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else {
|
||||
switch (cmd->param) {
|
||||
case L502_BF_CMD_ASYNC_TYPE_DOUT:
|
||||
async_dout(cmd->data[0], cmd->data_size >= 2 ? cmd->data[1] : 0);
|
||||
break;
|
||||
case L502_BF_CMD_ASYNC_TYPE_DAC1:
|
||||
async_dac_out(L502_DAC_CH1, cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_CMD_ASYNC_TYPE_DAC2:
|
||||
async_dac_out(L502_DAC_CH2, cmd->data[0]);
|
||||
break;
|
||||
default:
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
l502_cmd_done(err, NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_fpga_reg_wr(t_l502_bf_cmd *cmd) {
|
||||
int32_t err = 0;
|
||||
if (cmd->data_size < 1) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else if ((cmd->param & 0xFFFF0000) != 0) {
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
} else {
|
||||
fpga_reg_write(cmd->param, cmd->data[0]);
|
||||
}
|
||||
l502_cmd_done(err, NULL, 0);
|
||||
}
|
||||
|
||||
static void f_cmd_fpga_reg_rd(t_l502_bf_cmd *cmd) {
|
||||
int32_t err = 0;
|
||||
uint32_t val;
|
||||
if ((cmd->param & 0xFFFF0000) != 0) {
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
} else {
|
||||
val = fpga_reg_read(cmd->param);
|
||||
}
|
||||
l502_cmd_done(err, &val, 1);
|
||||
}
|
||||
|
||||
static void f_cmd_get_out_status(t_l502_bf_cmd *cmd) {
|
||||
uint32_t val = sport_tx_out_status();
|
||||
l502_cmd_done(0, &val, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Óñòàíîâêà ðàçëè÷íûõ ïàðàìåòðîâ.
|
||||
Êîä ïàðàìåòðà îïðåäåëÿåòñÿ ïî cmd->param, çíà÷åíèå áåðåòñÿ èç cmd->data
|
||||
â ñîîòâåòñòâèè ñ ïàðàìåòðîì */
|
||||
static void f_cmd_set_param(t_l502_bf_cmd *cmd) {
|
||||
int32_t err = g_mode != L502_BF_MODE_IDLE ? L502_BF_ERR_STREAM_RUNNING :
|
||||
cmd->data_size < 1 ? L502_BF_ERR_INSUF_CMD_DATA : 0;
|
||||
|
||||
if (!err) {
|
||||
switch (cmd->param) {
|
||||
case L502_BF_PARAM_MODULE_INFO:
|
||||
if (cmd->data_size > 0) {
|
||||
g_module_info.devflags = cmd->data[0];
|
||||
}
|
||||
if (cmd->data_size > 1) {
|
||||
g_module_info.fpga_ver = cmd->data[1] & 0xFFFF;
|
||||
g_module_info.plda_ver = (cmd->data[1]>>16) & 0xFF;
|
||||
}
|
||||
break;
|
||||
case L502_BF_PARAM_LCH_CNT:
|
||||
err = params_set_lch_cnt(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_LCH:
|
||||
/* ïàðàìåòðû: 0 - èíäåêñ, 1 - ôèç êàíàë, 2 - ðåæèì, 3 - äèàïàçîí, 4 - óñðåäåíåíèå */
|
||||
if (cmd->data_size < 5) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else {
|
||||
err = params_set_lch(cmd->data[0], cmd->data[1], (t_l502_lch_mode)cmd->data[2],
|
||||
(t_l502_adc_range)cmd->data[3], cmd->data[4],
|
||||
cmd->data_size>5 ? cmd->data[5] : 0);
|
||||
}
|
||||
break;
|
||||
case L502_BF_PARAM_ADC_FREQ_DIV:
|
||||
err = params_set_adc_freq_div(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_REF_FREQ_SRC:
|
||||
err = params_set_ref_freq(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_ADC_FRAME_DELAY:
|
||||
err = params_set_adc_interframe_delay(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_SYNC_MODE:
|
||||
err = params_set_sync_mode((t_l502_sync_mode)cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_SYNC_START_MODE:
|
||||
err = params_set_sync_start_mode((t_l502_sync_mode)cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_DIN_FREQ_DIV:
|
||||
err = params_set_din_freq_div(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_DAC_FREQ_DIV:
|
||||
err = params_set_dac_freq_div(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_IN_STEP_SIZE:
|
||||
err = sport_in_set_step_size(cmd->data[0]);
|
||||
break;
|
||||
case L502_BF_PARAM_ADC_COEF:
|
||||
if (cmd->data_size < 3) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else {
|
||||
uint32_t range = cmd->data[0];
|
||||
if (range >= L502_ADC_RANGE_CNT) {
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
} else {
|
||||
fpga_reg_write(f_regaddr_k[range], cmd->data[1]);
|
||||
fpga_reg_write(f_regaddr_offs[range], cmd->data[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L502_BF_PARAM_DAC_COEF:
|
||||
if (cmd->data_size < 3) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else {
|
||||
uint32_t ch = cmd->data[0];
|
||||
if (ch >= L502_DAC_CH_CNT) {
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
} else {
|
||||
float* pk = (float*)&cmd->data[1];
|
||||
float* po = (float*)&cmd->data[2];
|
||||
g_module_info.dac_cbr[ch].k = *pk;
|
||||
g_module_info.dac_cbr[ch].offs = *po;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
l502_cmd_done(err, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void f_cmd_get_param(t_l502_bf_cmd *cmd) {
|
||||
int32_t err = 0;
|
||||
uint32_t ret_size = 0;
|
||||
|
||||
|
||||
switch (cmd->param) {
|
||||
case L502_BF_PARAM_FIRM_VERSION:
|
||||
cmd->data[0] = L502_BF_FIRM_VERSION;
|
||||
cmd->data[1] = L502_BF_FIRM_FEATURES;
|
||||
ret_size = 2;
|
||||
break;
|
||||
case L502_BF_PARAM_STREAM_MODE:
|
||||
cmd->data[0] = g_mode;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_ENABLED_STREAMS:
|
||||
cmd->data[0] = g_streams;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_IN_BUF_SIZE:
|
||||
cmd->data[0] = sport_in_buffer_size();
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_LCH_CNT:
|
||||
cmd->data[0] = g_set.lch_cnt;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_LCH:
|
||||
if (cmd->data_size < 1) {
|
||||
err = L502_BF_ERR_INSUF_CMD_DATA;
|
||||
} else {
|
||||
uint32_t index = cmd->data[0];
|
||||
if (index >= L502_LTABLE_MAX_CH_CNT) {
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
} else {
|
||||
cmd->data[1] = g_set.lch[index].phy_ch;
|
||||
cmd->data[2] = g_set.lch[index].mode;
|
||||
cmd->data[3] = g_set.lch[index].range;
|
||||
cmd->data[4] = g_set.lch[index].avg;
|
||||
cmd->data[5] = g_set.lch[index].flags;
|
||||
ret_size = 6;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L502_BF_PARAM_ADC_FREQ_DIV:
|
||||
cmd->data[0] = g_set.adc_freq_div;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_REF_FREQ_SRC:
|
||||
cmd->data[0] = g_set.ref_freq;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_ADC_FRAME_DELAY:
|
||||
cmd->data[0] = g_set.adc_frame_delay;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_SYNC_MODE:
|
||||
cmd->data[0] = g_set.sync_mode;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_SYNC_START_MODE:
|
||||
cmd->data[0] = g_set.sync_start_mode;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_DIN_FREQ_DIV:
|
||||
cmd->data[0] = g_set.din_freq_div;
|
||||
ret_size = 1;
|
||||
break;
|
||||
case L502_BF_PARAM_DAC_FREQ_DIV:
|
||||
cmd->data[0] = g_set.out_freq_div;
|
||||
ret_size = 1;
|
||||
break;
|
||||
default:
|
||||
err = L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
break;
|
||||
}
|
||||
|
||||
l502_cmd_done(err, cmd->data, ret_size);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/** @defgroup cmd_process Обработка команд от ПК */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup cmd_process
|
||||
@{
|
||||
@file l502_cmd.h
|
||||
|
||||
Файл содержит описания функций, которые используются для обработки команд
|
||||
от ПК.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef L502_BF_CMD_H_
|
||||
#define L502_BF_CMD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "l502_bf_cmd_defs.h"
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Запуск обработки команды от ПК.
|
||||
|
||||
Функция начинает обработку команды от ПК, переданной по HDMA, вызывая нужный
|
||||
обработчик по коду команды.
|
||||
Вызывается из l502_cmd_check_req() при наличии запроса, но можно запустить
|
||||
и из самой прошивки выполнение команды, заполнив поля в g_state.cmd
|
||||
и вызвав l502_cmd_start().
|
||||
|
||||
Команда считается завершенной, когда будет вызвана l502_cmd_done(), которая
|
||||
может быть вызвана как из l502_cmd_start(), так и позже из другого места.
|
||||
|
||||
@param[in] cmd Структура, описывающая команду
|
||||
******************************************************************************/
|
||||
void l502_cmd_start(t_l502_bf_cmd* cmd);
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Завершение выполнения команды от ПК
|
||||
|
||||
Пометить комнду как завершенную, записав ее реультат и возвращаемые данные
|
||||
в фиксированную область. Если data уже указывает на g_state.cmd.data, т.е.
|
||||
данные уже находятся в нужной памяти, то они копироваться не будут
|
||||
|
||||
@param[in] result Код завершения команды
|
||||
@param[in] data Данные для ПК, возвращаемые командой
|
||||
@param[in] size Размер данных, возвращаемых командой (в 32-битных словах)
|
||||
*******************************************************************************/
|
||||
void l502_cmd_done(int32_t result, uint32_t* data, uint32_t size);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Проверка наличия команды от ПК
|
||||
*
|
||||
* Функция проверяет, есть ли команда от ПК для которой не была начата обработка
|
||||
* (был вызов l502_cmd_set_req(), но еще не был соответствующий вызов
|
||||
* l502_cmd_start()).
|
||||
*
|
||||
* Если есть необработанная команда, то для нее вызывается l502_cmd_start().
|
||||
*******************************************************************************/
|
||||
void l502_cmd_check_req(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Установка флага, что есть необработанная команда
|
||||
*
|
||||
* Функция вызвается из прерывания от HostDMA в случае, если при этой операции
|
||||
* HostDMA была записана команда. Функция устанавливает флаг, который будет
|
||||
* проверен уже из основной программы с помощью l502_cmd_check_req().
|
||||
******************************************************************************/
|
||||
void l502_cmd_set_req(void);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
/*********************************************************************//**
|
||||
@addtogroup config_params
|
||||
@{
|
||||
@file l502_defs.h Файл содержит определения,
|
||||
которые используются как программой BF, так и l502api,
|
||||
и кроме того видны программам, которые используют l502api
|
||||
@date 28.03.2012
|
||||
@author Borisov Alexey <borisov@lcard.ru>
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef L502_GLOBAL_DEFS_H_
|
||||
#define L502_GLOBAL_DEFS_H_
|
||||
|
||||
|
||||
/** Максимальное количество логических каналов в таблице*/
|
||||
#define L502_LTABLE_MAX_CH_CNT 256
|
||||
/** Количество диапазон для измерения напряжений */
|
||||
#define L502_ADC_RANGE_CNT 6
|
||||
|
||||
/** Код АЦП, соответствующий максимальному значению шкалы */
|
||||
#define L502_ADC_SCALE_CODE_MAX 6000000
|
||||
|
||||
/** Минимальное значение делителя частоты синхронного вывода */
|
||||
#define X502_OUT_FREQ_DIV_MIN 2
|
||||
/** Максимальное значение делителя частоты синхронного вывода */
|
||||
#define X502_OUT_FREQ_DIV_MAX 1024
|
||||
/** Значение делителя частоты вывода по умолчанию (которое также всегда
|
||||
используется в L502 с версией прошивки ПЛИС ниже 0.5) */
|
||||
#define X502_OUT_FREQ_DIV_DEFAULT 2
|
||||
|
||||
/** Максимальное значение для аппаратного устреднения по логическому каналу */
|
||||
#define L502_LCH_AVG_SIZE_MAX 128
|
||||
/** Максимальное значения делителя частоты АЦП */
|
||||
#define L502_ADC_FREQ_DIV_MAX (1024*1024)
|
||||
/** Максимальное значение делителя частоты синхронного цифрового ввода */
|
||||
#define L502_DIN_FREQ_DIV_MAX (1024*1024)
|
||||
|
||||
/** Максимальное значение межкадровой задержки для АЦП */
|
||||
#define L502_ADC_INTERFRAME_DELAY_MAX (0x1FFFFF)
|
||||
|
||||
|
||||
/** Диапазон ЦАП в вольтах */
|
||||
#define L502_DAC_RANGE 5.
|
||||
|
||||
/** Количество каналов ЦАП */
|
||||
#define L502_DAC_CH_CNT 2
|
||||
|
||||
/** Слово в потоке, означающее, что произошло переполнение */
|
||||
#define L502_STREAM_IN_MSG_OVERFLOW 0x01010000
|
||||
|
||||
|
||||
|
||||
|
||||
/** Флаги состояния для синхронного вывода */
|
||||
typedef enum {
|
||||
/** Флаг указывает, что в настоящее время буфер в модуле на передачу пуст */
|
||||
X502_OUT_STATUS_FLAG_BUF_IS_EMPTY = 0x01,
|
||||
/** Флаг указывает, что было опустошение буфера на вывод с начала старта синхронного
|
||||
ввода-вывода или с момента последнего чтения статуса с помощью
|
||||
X502_OutGetStatusFlags() (в зависимости от того, что было последним) */
|
||||
X502_OUT_STATUS_FLAG_BUF_WAS_EMPTY = 0x02
|
||||
} t_x502_out_status_flags;
|
||||
|
||||
/** @brief Флаги для управления цифровыми выходами.
|
||||
|
||||
Флаги управления цифровыми выходами. Могут быть объединены через логическое
|
||||
“ИЛИ” со значениями цифровых выходов при асинхронном выводе с помощью
|
||||
L502_AsyncOutDig() или переданы в L502_PrepareData() при синхронном выводе.*/
|
||||
typedef enum {
|
||||
L502_DIGOUT_WORD_DIS_H = 0x00020000, /**< Запрещение (перевод в третье состояние)
|
||||
старшей половины цифровых выходов */
|
||||
L502_DIGOUT_WORD_DIS_L = 0x00010000 /**< Запрещение младшей половины
|
||||
цифровых выходов */
|
||||
} t_l502_digout_word_flags;
|
||||
|
||||
|
||||
/** Константы для выбора опорной частоты */
|
||||
typedef enum {
|
||||
L502_REF_FREQ_2000KHZ = 2000000, /**< Частота 2МГц */
|
||||
L502_REF_FREQ_1500KHZ = 1500000 /**< Частота 1.5МГц */
|
||||
} t_l502_ref_freq;
|
||||
|
||||
|
||||
/** Диапазоны измерения для канала АЦП */
|
||||
typedef enum {
|
||||
L502_ADC_RANGE_10 = 0, /**< Диапазон +/-10V */
|
||||
L502_ADC_RANGE_5 = 1, /**< Диапазон +/-5V */
|
||||
L502_ADC_RANGE_2 = 2, /**< Диапазон +/-2V */
|
||||
L502_ADC_RANGE_1 = 3, /**< Диапазон +/-1V */
|
||||
L502_ADC_RANGE_05 = 4, /**< Диапазон +/-0.5V */
|
||||
L502_ADC_RANGE_02 = 5 /**< Диапазон +/-0.2V */
|
||||
} t_l502_adc_range;
|
||||
|
||||
/** Режим измерения для логического канала */
|
||||
typedef enum {
|
||||
L502_LCH_MODE_COMM = 0, /**< Измерение напряжения относительно общей земли */
|
||||
L502_LCH_MODE_DIFF = 1, /**< Дифференциальное измерение напряжения */
|
||||
L502_LCH_MODE_ZERO = 2 /**< Измерение собственного нуля */
|
||||
} t_l502_lch_mode;
|
||||
|
||||
/** @brief Режимы синхронизации.
|
||||
|
||||
Режимы задания источника частоты синхронизации и признака начала
|
||||
синхронного ввода-вывода */
|
||||
typedef enum {
|
||||
L502_SYNC_INTERNAL = 0, /**< Внутренний сигнал */
|
||||
L502_SYNC_EXTERNAL_MASTER = 1, /**< От внешнего мастера по разъему синхронизации */
|
||||
L502_SYNC_DI_SYN1_RISE = 2, /**< По фронту сигнала DI_SYN1 */
|
||||
L502_SYNC_DI_SYN2_RISE = 3, /**< По фронту сигнала DI_SYN2 */
|
||||
L502_SYNC_DI_SYN1_FALL = 6, /**< По спаду сигнала DI_SYN1 */
|
||||
L502_SYNC_DI_SYN2_FALL = 7 /**< По спаду сигнала DI_SYN2 */
|
||||
} t_l502_sync_mode;
|
||||
|
||||
|
||||
/** Флаги для обозначения синхронных потоков данных */
|
||||
typedef enum {
|
||||
L502_STREAM_ADC = 0x01, /**< Поток данных от АЦП */
|
||||
L502_STREAM_DIN = 0x02, /**< Поток данных с цифровых входов */
|
||||
L502_STREAM_DAC1 = 0x10, /**< Поток данных первого канала ЦАП */
|
||||
L502_STREAM_DAC2 = 0x20, /**< Поток данных второго канала ЦАП */
|
||||
L502_STREAM_DOUT = 0x40, /**< Поток данных на цифровые выводы */
|
||||
/** Объединение всех флагов, обозначающих потоки данных на ввод */
|
||||
L502_STREAM_ALL_IN = L502_STREAM_ADC | L502_STREAM_DIN,
|
||||
/** Объединение всех флагов, обозначающих потоки данных на вывод */
|
||||
L502_STREAM_ALL_OUT = L502_STREAM_DAC1 | L502_STREAM_DAC2 | L502_STREAM_DOUT
|
||||
} t_l502_streams;
|
||||
|
||||
#define L502_STREAM_OUT_WORD_TYPE_DOUT 0x0 /**< Тип передаваемого отсчета - цифровой вывод */
|
||||
#define L502_STREAM_OUT_WORD_TYPE_DAC1 0x40000000 /**< Тип передаваемого отсчета - Код для 1-го канала ЦАП */
|
||||
#define L502_STREAM_OUT_WORD_TYPE_DAC2 0x80000000 /**< Тип передаваемого отсчета - Код для 2-го канала ЦАП */
|
||||
|
||||
|
||||
/** Режим работы модуля L502 */
|
||||
typedef enum {
|
||||
L502_MODE_FPGA = 0, /**< Все потоки данных передаются через ПЛИС минуя
|
||||
сигнальный процессор BlackFin */
|
||||
L502_MODE_DSP = 1, /**< Все потоки данных передаются через сигнальный
|
||||
процессор, который должен быть загружен
|
||||
прошивкой для обработки этих потоков */
|
||||
L502_MODE_DEBUG = 2 /**< Отладочный режим */
|
||||
} t_l502_mode;
|
||||
|
||||
/** @brief Номера каналов ЦАП.
|
||||
|
||||
Номер каналов ЦАП для указания в L502_AsyncOutDac() */
|
||||
typedef enum {
|
||||
L502_DAC_CH1 = 0, /**< Первый канал ЦАП */
|
||||
L502_DAC_CH2 = 1 /**< Второй канал ЦАП */
|
||||
} t_l502_dac_ch;
|
||||
|
||||
|
||||
/** Флаги, описывающие модуль */
|
||||
typedef enum {
|
||||
/** Признак наличия ЦАП */
|
||||
L502_DEVFLAGS_DAC_PRESENT = 0x0001,
|
||||
/** Признак наличия гальваноразвязки */
|
||||
L502_DEVFLAGS_GAL_PRESENT = 0x0002,
|
||||
/** Признак наличия сигнального процессора */
|
||||
L502_DEVFLAGS_BF_PRESENT = 0x0004,
|
||||
/** Признак, что во Flash-памяти присутствует информация о модуле */
|
||||
L502_DEVFLAGS_FLASH_DATA_VALID = 0x00010000,
|
||||
/** Признак, что во Flash-памяти присутствуют действительные калибровочные
|
||||
коэффициенты АЦП */
|
||||
L502_DEVFLAGS_FLASH_ADC_CALIBR_VALID = 0x00020000,
|
||||
/** Признак, что во Flash-памяти присутствуют действительные калибровочные
|
||||
коэффициенты ЦАП */
|
||||
L502_DEVFLAGS_FLASH_DAC_CALIBR_VALID = 0x00040000
|
||||
} t_l502_devinfo_flags;
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,69 @@
|
||||
/** @addtogroup fpga_regs
|
||||
@{
|
||||
@file l502_fpga.c
|
||||
Ôàéë ñîäåðæèò ëîãèêó ïåðåäà÷è êîìàíä äëÿ ÷òåíèÿ/çàïèñè ðåãèñòðîâ
|
||||
ÏËÈÑ ïî SPI.
|
||||
Èçíà÷àëüíî SPI äîëæåí áûòü ïðîèíèöèàëèçèðîâàí ñ ïîìîùüþ fpga_spi_init().
|
||||
Ïîñëå ýòîãî ìîæíî îñóùåñòâëÿòü çàïèñü ñ ïîìîùüþ fpga_reg_write(), à
|
||||
÷òåíèå ñ ïîìîùüþ fpga_reg_read(). */
|
||||
|
||||
#include <cdefBF523.h>
|
||||
|
||||
#include "l502_fpga.h"
|
||||
|
||||
#define L502_SPI_BIT_START 0x8000UL
|
||||
#define L502_SPI_BIT_WR 0x4000UL
|
||||
#define L502_SPI_MSK_ADDR 0x3FFFUL
|
||||
|
||||
|
||||
static uint16_t f_spi_rw(uint16_t word) {
|
||||
/* åñëè â áûëî ïðèíÿòî óæå ñëîâî - òî ÷èòàåì åãî, ÷òîáû îñâîáîäèòü áóôåð ïðèåìà */
|
||||
if (*pSPI_STAT & RXS) {
|
||||
volatile uint16_t dummy;
|
||||
dummy = *pSPI_RDBR;
|
||||
}
|
||||
|
||||
*pSPI_TDBR = word;
|
||||
/* æäåì ïîêà ïðèìåì íîâîå ñëîâî */
|
||||
while (!(*pSPI_STAT&RXS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return *pSPI_RDBR;
|
||||
}
|
||||
|
||||
|
||||
void fpga_spi_init(void) {
|
||||
/* íàñòðîéêà SPI */
|
||||
*pSPI_BAUD = 2; /* SPI CLK = 132.5/(2*2) = 33.125 */
|
||||
*pSPI_CTL = SPE | MSTR | SIZE | GM | TDBR_CORE; /* Ìàñòåð, MSB first, 16-bit, CPHA=0, CPOL=0 */
|
||||
*pSPI_FLG = FLS1;
|
||||
|
||||
*pPORTG_MUX = (*pPORTG_MUX & 0xFFFC) | 2;
|
||||
*pPORTG_FER |= PG1 | PG2 | PG3 | PG4;
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, 0);
|
||||
}
|
||||
|
||||
|
||||
void fpga_reg_write(uint16_t addr, uint32_t value) {
|
||||
f_spi_rw((addr&L502_SPI_MSK_ADDR) | L502_SPI_BIT_START | L502_SPI_BIT_WR);
|
||||
f_spi_rw((value>>24)&0xFF);
|
||||
f_spi_rw((value>>16)&0xFF);
|
||||
f_spi_rw((value>>8)&0xFF);
|
||||
f_spi_rw(value&0xFF);
|
||||
}
|
||||
|
||||
|
||||
uint32_t fpga_reg_read(uint16_t addr) {
|
||||
uint32_t ret = 0;
|
||||
f_spi_rw((addr&L502_SPI_MSK_ADDR) | L502_SPI_BIT_START);
|
||||
f_spi_rw(0);
|
||||
f_spi_rw(0);
|
||||
ret = f_spi_rw(0);
|
||||
ret <<= 16;
|
||||
ret |= f_spi_rw(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,31 @@
|
||||
/** @defgroup fpga_regs Доступ к регистрам ПЛИС */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup fpga_regs
|
||||
@{
|
||||
@file l502_fpga.h
|
||||
Файл содержит функции для записи и чтения регистров ПЛИС по интерфейсу АЦП
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef L502_FPGA_H_
|
||||
#define L502_FPGA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "l502_fpga_regs.h"
|
||||
|
||||
/** Инициализация SPI интерфейса */
|
||||
void fpga_spi_init(void);
|
||||
|
||||
/** Запись регистра в регистр ПЛИС значения по интерфейсу SPI
|
||||
@param[in] addr Адрес регистра ПЛИС
|
||||
@param[in] value Записываемое значение */
|
||||
void fpga_reg_write(uint16_t addr, uint32_t value);
|
||||
/** Чтение значения из регистра ПЛИС по интерфейсу SPI
|
||||
@param[in] addr Адрес регистра ПЛИС
|
||||
@return Прочитанное значение */
|
||||
uint32_t fpga_reg_read(uint16_t addr);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,208 @@
|
||||
#ifndef L5XX_REGS_H
|
||||
#define L5XX_REGS_H
|
||||
|
||||
#define L583_BF_ADDR_ENDPROG (0xFFFFFFFCUL)
|
||||
|
||||
|
||||
#define L502_MAX_PAGES_CNT 252
|
||||
|
||||
#define L502_BF_SDRAM_SIZE (32UL*1024*1024)
|
||||
|
||||
#define L502_BF_MEMADDR_CMD 0xFF800800
|
||||
|
||||
|
||||
#define L502_BF_CMD_READ 0x0001
|
||||
#define L502_BF_CMD_WRITE 0x0002
|
||||
#define L502_BF_CMD_HIRQ 0x0004
|
||||
#define L502_BF_CMD_HDMA_RST 0x0008
|
||||
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ áëîêà EEPROM *************************/
|
||||
#define L502_REGS_EEPROM_BLOCK 0x0100
|
||||
|
||||
#define L502_REGS_EEPROM_SET_RD_ADDR (L502_REGS_EEPROM_BLOCK + 0)
|
||||
#define L502_REGS_EEPROM_RD_DWORD (L502_REGS_EEPROM_BLOCK + 1)
|
||||
#define L502_REGS_EEPROM_RD_STATUS (L502_REGS_EEPROM_BLOCK + 2)
|
||||
#define L502_REGS_EEPROM_WR_STATUS_EN (L502_REGS_EEPROM_BLOCK + 3)
|
||||
#define L502_REGS_EEPROM_WR_EN (L502_REGS_EEPROM_BLOCK + 4)
|
||||
#define L502_REGS_EEPROM_WR_DIS (L502_REGS_EEPROM_BLOCK + 5)
|
||||
#define L502_REGS_EEPROM_WR_STATUS (L502_REGS_EEPROM_BLOCK + 6)
|
||||
#define L502_REGS_EEPROM_ERASE_4K (L502_REGS_EEPROM_BLOCK + 7)
|
||||
#define L502_REGS_EEPROM_ERASE_64K (L502_REGS_EEPROM_BLOCK + 8)
|
||||
#define L502_REGS_EEPROM_WR_BYTE (L502_REGS_EEPROM_BLOCK + 9)
|
||||
#define L502_REGS_EEPROM_HARD_WR_STATUS_EN (L502_REGS_EEPROM_BLOCK + 0xF)
|
||||
#define L502_REGS_HARD_ID (L502_REGS_EEPROM_BLOCK + 0xA)
|
||||
#define L502_REGS_JEDEC_RD_ID (L502_REGS_EEPROM_BLOCK + 0xB)
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ ñ îòëàäî÷íîé èíôîðìàöèåé **************/
|
||||
#define L502_REGS_DBG_BLOCK 0x0140
|
||||
#define L502_REGS_DBG_EVENTS (L502_REGS_DBG_BLOCK + 0)
|
||||
#define L502_REGS_DBG_LAST_ABORT_ADDR (L502_REGS_DBG_BLOCK + 8)
|
||||
#define L502_REGS_DBG_LAST_NACK_ADDR (L502_REGS_DBG_BLOCK + 9)
|
||||
#define L502_REGS_DBG_LINK_REPLAY_CNT (L502_REGS_DBG_BLOCK + 10)
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ áëîêà IOHARD **************************/
|
||||
#define L502_REGS_IOHARD_BLOCK 0x0200
|
||||
//Àäðåñ Control Table
|
||||
#define L502_REGS_IOHARD_LTABLE (L502_REGS_IOHARD_BLOCK+0)
|
||||
#define L502_REGS_IOHARD_LTABLE_MAX_SIZE 0x100 // Ìàêñèìàëüíûé ðàçìåð Control Table
|
||||
|
||||
#define L502_REGS_IOHARD_LCH_CNT (L502_REGS_IOHARD_BLOCK+0x100)
|
||||
#define L502_REGS_IOHARD_ADC_FREQ_DIV (L502_REGS_IOHARD_BLOCK+0x102)
|
||||
#define L502_REGS_IOHARD_ADC_FRAME_DELAY (L502_REGS_IOHARD_BLOCK+0x104)
|
||||
#define L502_REGS_IOHARD_DIGIN_FREQ_DIV (L502_REGS_IOHARD_BLOCK+0x106)
|
||||
#define L502_REGS_IOHARD_IO_MODE (L502_REGS_IOHARD_BLOCK+0x108)
|
||||
#define L502_REGS_IOHARD_GO_SYNC_IO (L502_REGS_IOHARD_BLOCK+0x10A)
|
||||
#define L502_REGS_IOHARD_PRELOAD_ADC (L502_REGS_IOHARD_BLOCK+0x10C)
|
||||
#define L502_REGS_IOHARD_ASYNC_OUT (L502_REGS_IOHARD_BLOCK+0x112)
|
||||
#define L502_REGS_IOHARD_LED (L502_REGS_IOHARD_BLOCK+0x114)
|
||||
#define L502_REGS_IOHARD_DIGIN_PULLUP (L502_REGS_IOHARD_BLOCK+0x116)
|
||||
#define L502_REGS_IOHARD_OUTSWAP_BFCTL (L502_REGS_IOHARD_BLOCK+0x118)
|
||||
#define L502_REGS_IOHARD_OUTSWAP_ERROR (L502_REGS_IOHARD_BLOCK+0x120)
|
||||
|
||||
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ áëîêà IOARITH **************************/
|
||||
#define L502_REGS_IOARITH_BLOCK 0x0400
|
||||
#define L502_REGS_IOARITH_B10 L502_REGS_IOARITH_BLOCK
|
||||
#define L502_REGS_IOARITH_B5 (L502_REGS_IOARITH_BLOCK+0x01)
|
||||
#define L502_REGS_IOARITH_B2 (L502_REGS_IOARITH_BLOCK+0x02)
|
||||
#define L502_REGS_IOARITH_B1 (L502_REGS_IOARITH_BLOCK+0x03)
|
||||
#define L502_REGS_IOARITH_B05 (L502_REGS_IOARITH_BLOCK+0x04)
|
||||
#define L502_REGS_IOARITH_B02 (L502_REGS_IOARITH_BLOCK+0x05)
|
||||
#define L502_REGS_IOARITH_K10 (L502_REGS_IOARITH_BLOCK+0x08)
|
||||
#define L502_REGS_IOARITH_K5 (L502_REGS_IOARITH_BLOCK+0x09)
|
||||
#define L502_REGS_IOARITH_K2 (L502_REGS_IOARITH_BLOCK+0x0A)
|
||||
#define L502_REGS_IOARITH_K1 (L502_REGS_IOARITH_BLOCK+0x0B)
|
||||
#define L502_REGS_IOARITH_K05 (L502_REGS_IOARITH_BLOCK+0x0C)
|
||||
#define L502_REGS_IOARITH_K02 (L502_REGS_IOARITH_BLOCK+0x0D)
|
||||
#define L502_REGS_IOARITH_ADC_FREQ_DIV (L502_REGS_IOARITH_BLOCK+0x12)
|
||||
#define L502_REGS_IOARITH_IN_STREAM_ENABLE (L502_REGS_IOARITH_BLOCK+0x19)
|
||||
#define L502_REGS_IOARITH_DIN_ASYNC (L502_REGS_IOARITH_BLOCK+0x1A)
|
||||
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ áëîêà óïðàâëåíèÿ BlackFin'îì **********/
|
||||
#define L502_REGS_BF_CTL_BLOCK 0
|
||||
#define L502_REGS_BF_CTL (L502_REGS_BF_CTL_BLOCK+0)
|
||||
#define L502_REGS_BF_CMD (L502_REGS_BF_CTL_BLOCK+1)
|
||||
#define L502_REGS_BF_STATUS (L502_REGS_BF_CTL_BLOCK+2)
|
||||
#define L502_REGS_BF_IRQ (L502_REGS_BF_CTL_BLOCK+3)
|
||||
#define L502_REGS_BF_IRQ_EN (L502_REGS_BF_CTL_BLOCK+4)
|
||||
#define L502_REGS_BF_REQ_ADDR (L502_REGS_BF_CTL_BLOCK+5)
|
||||
#define L502_REGS_BF_REQ_SIZE (L502_REGS_BF_CTL_BLOCK+6)
|
||||
#define L502_REGS_BF_REQ_DATA (L502_REGS_BF_CTL_BLOCK+128)
|
||||
|
||||
#define L502_BF_REQ_DATA_SIZE_MAX 128
|
||||
#define L502_BF_REQ_DATA_SIZE_MIN 8
|
||||
|
||||
|
||||
/********************* Àäðåñà ðåãèñòðîâ áëîêà DMA *****************************/
|
||||
#define L502_REGS_DMA_CTL_BLOCK 0x700
|
||||
#define L502_REGS_DMA_CAP (L502_REGS_DMA_CTL_BLOCK)
|
||||
#define L502_REGS_DMA_EN (L502_REGS_DMA_CTL_BLOCK+1)
|
||||
#define L502_REGS_DMA_DIS (L502_REGS_DMA_CTL_BLOCK+2)
|
||||
#define L502_REGS_DMA_RST (L502_REGS_DMA_CTL_BLOCK+3)
|
||||
#define L502_REGS_DMA_IRQ (L502_REGS_DMA_CTL_BLOCK+4)
|
||||
#define L502_REGS_DMA_IRQ_EN (L502_REGS_DMA_CTL_BLOCK+5)
|
||||
#define L502_REGS_DMA_IRQ_DIS (L502_REGS_DMA_CTL_BLOCK+6)
|
||||
|
||||
#define L502_REGS_DMA_CH_PARAMS_SIZE (16 + L502_MAX_PAGES_CNT*4)
|
||||
#define L502_DMA_CHNUM_IN 0
|
||||
#define L502_DMA_CHNUM_OUT 1
|
||||
|
||||
/* íîìåð ðåãèñòðà, ñ êîòîðîãî íà÷èíàþòñÿ ïàðàìåòðû êàíàëà DMA */
|
||||
#define L502_REGS_DMA_CH_PARAMS(ch) (0x800 + L502_REGS_DMA_CH_PARAMS_SIZE*ch)
|
||||
#define L502_REGS_DMA_CH_CTL(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 0)
|
||||
#define L502_REGS_DMA_CH_CMP_CNTR(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 1)
|
||||
#define L502_REGS_DMA_CH_CUR_CNTR(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 2)
|
||||
#define L502_REGS_DMA_CH_CUR_POS(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 3)
|
||||
#define L502_REGS_DMA_CH_PC_POS(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 4)
|
||||
|
||||
|
||||
/* àäðåñà äëÿ ðåãèñòðîâ ñòðàíèö DMA ÀÖÏ */
|
||||
#define L502_REGS_DMA_CH_PAGES(ch) (L502_REGS_DMA_CH_PARAMS(ch) + 16)
|
||||
#define L502_REGS_DMA_CH_PAGE_ADDRL(ch,n) (L502_REGS_DMA_CH_PAGES(ch) + 4*(n))
|
||||
#define L502_REGS_DMA_CH_PAGE_ADDRH(ch,n) (L502_REGS_DMA_CH_PAGES(ch) + 4*(n)+1)
|
||||
#define L502_REGS_DMA_CH_PAGE_LEN(ch,n) (L502_REGS_DMA_CH_PAGES(ch) + 4*(n)+2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define L502_REGBIT_BF_STATUS_HWAIT_Pos 0
|
||||
#define L502_REGBIT_BF_STATUS_HWAIT_Msk (1UL << L502_REGBIT_BF_STATUS_HWAIT_Pos)
|
||||
|
||||
#define L502_REGBIT_BF_STATUS_BUSY_Pos 1
|
||||
#define L502_REGBIT_BF_STATUS_BUSY_Msk (1UL << L502_REGBIT_BF_STATUS_BUSY_Pos)
|
||||
|
||||
|
||||
/* îïèñàíèå îòäåëüíûõ áèòîâ ðåãèñòðîâ */
|
||||
#define L502_REGBIT_DMA_CTL_PACK_SIZE_Pos 0
|
||||
#define L502_REGBIT_DMA_CTL_PACK_SIZE_Msk (0xFFUL << L502_REGBIT_DMA_CTL_PACK_SIZE_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CTL_PAGE_CNT_Pos 16
|
||||
#define L502_REGBIT_DMA_CTL_PAGE_CNT_Msk (0xFFUL << L502_REGBIT_DMA_CTL_PAGE_CNT_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CTL_AUTOSTOP_Pos 31
|
||||
#define L502_REGBIT_DMA_CTL_AUTOSTOP_Msk (0x1UL << L502_REGBIT_DMA_CTL_AUTOSTOP_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CTL_PC_WAIT_Pos 30
|
||||
#define L502_REGBIT_DMA_CTL_PC_WAIT_Msk (0x1UL << L502_REGBIT_DMA_CTL_PC_WAIT_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CH_ADC_Pos 0
|
||||
#define L502_REGBIT_DMA_CH_ADC_Msk (0x1UL << L502_REGBIT_DMA_CH_ADC_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CH_DAC_Pos 1
|
||||
#define L502_REGBIT_DMA_CH_DAC_Msk (0x1UL << L502_REGBIT_DMA_CH_DAC_Pos)
|
||||
|
||||
|
||||
|
||||
#define L502_REGBIT_BF_CTL_BF_RESET_Pos 1
|
||||
#define L502_REGBIT_BF_CTL_BF_RESET_Msk (0x1UL << L502_REGBIT_BF_CTL_BF_RESET_Pos)
|
||||
|
||||
|
||||
#define L502_REGBIT_BF_CTL_HOST_WAIT_Pos 3
|
||||
#define L502_REGBIT_BF_CTL_HOST_WAIT_Msk (0x1UL << L502_REGBIT_BF_CTL_HOST_WAIT_Pos)
|
||||
|
||||
#define L502_REGBIT_BF_CTL_DSP_MODE_Pos 4
|
||||
#define L502_REGBIT_BF_CTL_DSP_MODE_Msk (0x1UL << L502_REGBIT_BF_CTL_DSP_MODE_Pos)
|
||||
|
||||
#define L502_REGBIT_BF_CTL_DBG_MODE_Pos 5
|
||||
#define L502_REGBIT_BF_CTL_DBG_MODE_Msk (0x1UL << L502_REGBIT_BF_CTL_DBG_MODE_Pos)
|
||||
|
||||
#define L502_REGBIT_BF_CTL_CLK_DIV_Pos 8
|
||||
#define L502_REGBIT_BF_CTL_CLK_DIV_Msk (0xFUL << L502_REGBIT_BF_CTL_CLK_DIV_Pos)
|
||||
|
||||
#define L502_REGBIT_DMA_CURPOS_PAGE_Pos 24
|
||||
#define L502_REGBIT_DMA_CURPOS_PAGE_Msk (0xFFUL << L502_REGBIT_DMA_CURPOS_PAGE_Pos)
|
||||
|
||||
#define L502_REGBIT_ADC_SLV_CLK_LOCK_Pos 31
|
||||
#define L502_REGBIT_ADC_SLV_CLK_LOCK_Msk (0x1UL << L502_REGBIT_ADC_SLV_CLK_LOCK_Pos)
|
||||
|
||||
|
||||
|
||||
#define L502_REGBIT_IOHARD_OUT_SWAP_Pos 0
|
||||
#define L502_REGBIT_IOHARD_OUT_SWAP_Msk (0x1UL << L502_REGBIT_IOHARD_OUT_SWAP_Pos)
|
||||
|
||||
#define L502_REGBIT_IOHARD_OUT_TFS_EN_Pos 1
|
||||
#define L502_REGBIT_IOHARD_OUT_TFS_EN_Msk (0x1UL << L502_REGBIT_IOHARD_OUT_TFS_EN_Pos)
|
||||
|
||||
#define L502_REGBIT_IOHARD_OUT_RING_Pos 2
|
||||
#define L502_REGBIT_IOHARD_OUT_RING_Msk (0x1UL << L502_REGBIT_IOHARD_OUT_RING_Pos)
|
||||
|
||||
#define L502_REGBIT_IOHARD_OUT_RFS_EN_Pos 3
|
||||
#define L502_REGBIT_IOHARD_OUT_RFS_EN_Msk (0x1UL << L502_REGBIT_IOHARD_OUT_RFS_EN_Pos)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define L502_REGBIT_DMA_IRQ_STEP_Msk(ch) (1UL << ch)
|
||||
#define L502_REGBIT_DMA_IRQ_PAGE_Msk(ch) (1UL << (ch+8))
|
||||
|
||||
|
||||
|
||||
#endif // L5XX_REGS_H
|
||||
@@ -0,0 +1,77 @@
|
||||
/** @defgroup global_defs Фиксированная область памяти */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup global_defs
|
||||
@{
|
||||
@file l502_global.h
|
||||
Файл содержит определение структур, описывающих область памяти
|
||||
BlackFin с фиксированными адресами:
|
||||
- Структуры дескрипторов для передачи потоков данных по HostDMA
|
||||
- Структру для передачи команд от ПК к BlackFin
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef L502_GLOBAL_H_
|
||||
#define L502_GLOBAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "l502_bf_cmd_defs.h"
|
||||
|
||||
|
||||
/** Версия прошивки BlackFin */
|
||||
#define L502_BF_FIRM_VERSION 0x00000002
|
||||
|
||||
/** Дополнительные возможности, реализованные в прошивке */
|
||||
#define L502_BF_FIRM_FEATURES (L502_BF_FEATURE_FPGA_REG_ACCESS | L502_BF_FEATURE_OUT_STATUS_FLAGS)
|
||||
|
||||
|
||||
/** Структура дескриптора для передачи потока по HostDMA */
|
||||
typedef struct {
|
||||
uint32_t flags; /**< Флаги */
|
||||
uint32_t full_size; /**< Полный размер передачи */
|
||||
void* addr; /**< Начальный адрес данных для передачи */
|
||||
uint16_t xcnt; /**< Кол-во 16-разрядных слов в одном передаваемом блоке */
|
||||
uint16_t xmod; /**< Модификатор указателя */
|
||||
uint16_t ycnt; /**< Не используется */
|
||||
uint16_t ymod; /**< Не используется */
|
||||
void* next_descr; /**< Указатель на следующий дескриптор */
|
||||
uint16_t id; /**< id-номер дескриптора */
|
||||
uint16_t valid; /**< Признак действительности */
|
||||
uint32_t udata; /**< Доп данные */
|
||||
} t_hdma_stream_descr;
|
||||
|
||||
|
||||
/** Максимальное количество дескрипторов на передачу данных (Bf->ПК) */
|
||||
#define L502_IN_HDMA_DESCR_CNT (31)
|
||||
/** Максимальное количество дескрипторов на прием данных (ПК->Bf) */
|
||||
#define L502_OUT_HDMA_DESCR_CNT (31)
|
||||
|
||||
|
||||
/** @brief Описание массива дескрипторов HDMA
|
||||
|
||||
Структура описывает расположение дескрипторов HostDMA для организации
|
||||
потока данных между BlackFin и персональным компьютером как на передачу,
|
||||
так и на прием */
|
||||
typedef struct {
|
||||
t_hdma_stream_descr in_lb; /**< Последний выполненный дескриптор на ввод */
|
||||
t_hdma_stream_descr in[L502_IN_HDMA_DESCR_CNT]; /**< Список дескрипторов на ввод */
|
||||
t_hdma_stream_descr out_lb; /**< Последний выполненный дескриптор на вывод */
|
||||
t_hdma_stream_descr out[L502_OUT_HDMA_DESCR_CNT]; /**< Список дескрипторов на вывод */
|
||||
} t_hdma_descr_arr;
|
||||
|
||||
|
||||
/** @brief Описание фиксированной области памяти
|
||||
|
||||
Структура описывает данные в памяти сигнального процессора, которые должны
|
||||
быть расположены по фиксированным адресам */
|
||||
typedef struct {
|
||||
t_hdma_descr_arr hdma; /**< 0xFF800000 - дескрипторы для обмена потоком по HDMA*/
|
||||
t_l502_bf_cmd cmd; /**< 0xFF800800 - команда обмена с PC*/
|
||||
} t_l502_board_state;
|
||||
|
||||
/** Структура, содержащая данные фиксированной памяти */
|
||||
extern volatile t_l502_board_state g_state;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** @} */
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/***************************************************************************//**
|
||||
@addtogroup hdma
|
||||
@{
|
||||
@file l502_hdma.c
|
||||
Файл содержит логику работы с hdma на прием и на передачу данных
|
||||
как из, так и в BlackFin.
|
||||
***************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
При запуске должно вызываться один раз hdma_stream_init().
|
||||
Вызов hdma_xxx_start() инициализирует прием или передачу, а hdma_xxx_stop()
|
||||
останавливает все текущие передачи.
|
||||
|
||||
Для запуска обмена блоком данных нужно проверить готовность
|
||||
(наличие свободных дескрипторов) с помощью hdma_xxx_req_rdy()
|
||||
и вызвать hdma_xxx_req_start(), указав массив для передачи или приема
|
||||
данных и его размер.
|
||||
|
||||
Можно устанавливать до 31 запроса в очередь.
|
||||
|
||||
По завершению обмена будет вызвана функция hdma_xxx_done(), которая
|
||||
должна быть реализована в другом файле. Для передачи BF->PC
|
||||
функция вызывается один раз на каждый поставленный запрос,
|
||||
а при приеме PC->BF может вызываться по несколько раз - при приеме
|
||||
части запроса (в случае, если от PC пока нет больше данных)
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#include "l502_global.h"
|
||||
#include "l502_cdefs.h"
|
||||
#include "l502_cmd.h"
|
||||
|
||||
|
||||
#include <cdefBF523.h>
|
||||
#include <sys/exception.h>
|
||||
#include <ccblkfn.h>
|
||||
|
||||
|
||||
#define STREAM_IN_EN() *pPORTFIO_CLEAR = PF14
|
||||
#define STREAM_IN_DIS() *pPORTFIO_SET = PF14
|
||||
#define STREAM_OUT_EN() *pPORTFIO_CLEAR = PF15
|
||||
#define STREAM_OUT_DIS() *pPORTFIO_SET = PF15
|
||||
|
||||
#define STREAM_IN_SET_REQ() *pPORTGIO_TOGGLE = PG5
|
||||
#define STREAM_OUT_SET_REQ() *pPORTGIO_TOGGLE = PG6
|
||||
|
||||
|
||||
|
||||
#define L502_HDMA_STEP_SIZE_MAX 256
|
||||
|
||||
|
||||
static uint16_t f_snd_start_id, f_rcv_start_id;
|
||||
static uint16_t f_snd_done_id, f_rcv_done_id;
|
||||
static uint8_t f_snd_next_descr, f_rcv_next_descr;
|
||||
static uint8_t f_rcv_done_descr;
|
||||
|
||||
|
||||
void hdma_send_done(uint32_t* addr, uint32_t size);
|
||||
void hdma_recv_done(uint32_t* addr, uint32_t size);
|
||||
|
||||
|
||||
ISR(hdma_isr);
|
||||
ISR(hdma_rd_isr);
|
||||
|
||||
|
||||
|
||||
|
||||
inline static void hdma_set_descr(t_hdma_stream_descr* descr_arr, uint8_t* pos,
|
||||
uint16_t* id, uint32_t* addr, uint32_t size, uint32_t flags) {
|
||||
descr_arr[*pos].flags = flags;
|
||||
descr_arr[*pos].addr = addr;
|
||||
descr_arr[*pos].id = *id;
|
||||
descr_arr[*pos].full_size = size*2;
|
||||
descr_arr[*pos].xcnt = size > L502_HDMA_STEP_SIZE_MAX ? 2*L502_HDMA_STEP_SIZE_MAX : 2*size;
|
||||
descr_arr[*pos].udata = size;
|
||||
*id = *id+1;
|
||||
|
||||
*pos=*pos+1;
|
||||
if (*pos== L502_IN_HDMA_DESCR_CNT)
|
||||
*pos = 0;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Инициализация интерфейса HostDMA
|
||||
|
||||
Настройка параметров HostDMA и инициализация неизменяемых полей дескрипторов
|
||||
для организации потока по данных по HostDMA */
|
||||
void hdma_init(void) {
|
||||
int d;
|
||||
|
||||
/* запрещаем ПЛИС отслеживать запросы на обмен по HDMA */
|
||||
STREAM_IN_DIS();
|
||||
STREAM_OUT_DIS();
|
||||
|
||||
*pPORTGIO_DIR |= PG5 | PG6;
|
||||
*pPORTFIO_DIR |= PF14 | PF15;
|
||||
|
||||
/***************** настройка HOST DMA ***********************/
|
||||
//настройка портов
|
||||
*pPORTG_MUX |= 0x2800;
|
||||
*pPORTG_FER |= 0xF800;
|
||||
*pPORTH_MUX = 0x2A;
|
||||
*pPORTH_FER = 0xFFFF;
|
||||
|
||||
|
||||
//настройка прерываний
|
||||
REGISTER_ISR(11, hdma_isr);
|
||||
//*pSIC_IAR3 = (*pSIC_IAR6 & 0xFFF0FFFFUL) | (3 << 16);
|
||||
*pSIC_IAR6 = (*pSIC_IAR6 & 0xFFFFF0FFUL) | P50_IVG(10); //назначение HDMARD на IVG10
|
||||
REGISTER_ISR(10, hdma_rd_isr);
|
||||
*pSIC_IMASK0 |= IRQ_DMA1; //разрешение прерывания HOSTDP на запись
|
||||
*pSIC_IMASK1 |= IRQ_HOSTRD_DONE; //разрешение прерывания HOSTDP на чтение;
|
||||
//разрешение HDMA
|
||||
*pHOST_CONTROL = BDR | EHR | EHW | HOSTDP_EN | HOSTDP_DATA_SIZE; //burst, ehr, ehw, en
|
||||
|
||||
//g_state.cmd.data[100] = L502_BF_CMD_STATUS_DONE;
|
||||
|
||||
/* инициалзация полей дескрипторов, которые не будут изменяться
|
||||
во время работы */
|
||||
for (d=0; d < L502_IN_HDMA_DESCR_CNT; d++) {
|
||||
g_state.hdma.in[d].xmod = 2;
|
||||
g_state.hdma.in[d].valid = 1;
|
||||
g_state.hdma.in[d].next_descr = d==( L502_IN_HDMA_DESCR_CNT-1) ?
|
||||
(void*)&g_state.hdma.in[0] : (void*)&g_state.hdma.in[d+1];
|
||||
}
|
||||
|
||||
for (d=0; d < L502_OUT_HDMA_DESCR_CNT; d++) {
|
||||
g_state.hdma.out[d].xmod = 2;
|
||||
g_state.hdma.out[d].valid = 1;
|
||||
g_state.hdma.out[d].next_descr = d==( L502_IN_HDMA_DESCR_CNT-1) ?
|
||||
(void*)&g_state.hdma.out[0] : (void*)&g_state.hdma.out[d+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Запуск потока на передачу по HostDMA.
|
||||
|
||||
Функция сбрасывает логику обработки заданий на передачу данных по HostDMA
|
||||
и разрешает передачу. Должна вызываться до добавления первого задания с помощью
|
||||
hdma_send_req_start() */
|
||||
void hdma_send_start(void) {
|
||||
f_snd_start_id = 0;
|
||||
f_snd_done_id = 0;
|
||||
f_snd_next_descr = 0;
|
||||
|
||||
g_state.hdma.in_lb.valid = 0;
|
||||
|
||||
STREAM_IN_EN();
|
||||
}
|
||||
|
||||
/** @brief Останов потока на передачу по HostDMA.
|
||||
|
||||
Запрет передачи по HostDMA с остановом всех текущих заданий */
|
||||
void hdma_send_stop(void) {
|
||||
STREAM_IN_DIS();
|
||||
}
|
||||
|
||||
/** @brief Запуск потока на прием по HostDMA
|
||||
|
||||
Функция сбрасывает логику обработки заданий на прием данных по HostDMA
|
||||
и разрешает прием. Должна вызываться до добавления первого задания с помощью
|
||||
hdma_recv_req_start() */
|
||||
void hdma_recv_start(void) {
|
||||
f_rcv_start_id = 0;
|
||||
f_rcv_done_id = 0;
|
||||
f_rcv_next_descr = 0;
|
||||
f_rcv_done_descr = 0;
|
||||
|
||||
g_state.hdma.out_lb.valid = 0;
|
||||
STREAM_OUT_EN();
|
||||
}
|
||||
|
||||
/** @brief Останов потока на прием по HostDMA
|
||||
|
||||
Запрет приема по HostDMA с остановом всех текущих заданий */
|
||||
void hdma_recv_stop(void) {
|
||||
STREAM_OUT_DIS();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Получить количество свободных запросов на передачу.
|
||||
|
||||
Фунция позволяет узнать, сколько запросов можно еще поставить в очередь на
|
||||
передачу с помощью hdma_send_start().
|
||||
@return Количество запросов на передачу, которое можно поставить в очередь
|
||||
******************************************************************************/
|
||||
int hdma_send_req_rdy(void) {
|
||||
return L502_IN_HDMA_DESCR_CNT - (uint16_t)(f_snd_start_id - f_snd_done_id);
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Получить количество свободных запросов на прием
|
||||
|
||||
Фунция позволяет узнать, сколько запросов можно еще поставить в очередь на
|
||||
прием с помощью hdma_recv_start().
|
||||
@return Количество запросов на прием, которое можно поставить в очередь
|
||||
******************************************************************************/
|
||||
int hdma_recv_req_rdy(void) {
|
||||
return L502_OUT_HDMA_DESCR_CNT - (uint16_t)(f_rcv_start_id - f_rcv_done_id);
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Поставить запрос на передачу по HostDMA
|
||||
|
||||
Функция ставит запрос на передачу указанных данных. Сами данные не копируются,
|
||||
т.е. буфер нельзя будет использовать до того, как данные не будут переданы!
|
||||
Для постановки запроса необходимо, чтобы был свободный дескриптор (можно
|
||||
узнать через hdma_send_req_rdy())
|
||||
|
||||
@param[in] buf Указатель на массив на передачу.
|
||||
@param[in] size Количество 32-битных слов на передачу
|
||||
@param[in] flags Флаги из #t_hdma_send_flags
|
||||
@return < 0 при ошибке, >= 0 - id передачи при успехе
|
||||
*******************************************************************************/
|
||||
int hdma_send_req_start(const uint32_t* buf, uint32_t size, uint32_t flags) {
|
||||
if (hdma_send_req_rdy() > 0) {
|
||||
hdma_set_descr((t_hdma_stream_descr*)g_state.hdma.in, &f_snd_next_descr, &f_snd_start_id,
|
||||
(uint32_t*)buf, size, flags);
|
||||
STREAM_IN_SET_REQ();
|
||||
return f_snd_start_id-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Поставить запрос на передачу по HostDMA
|
||||
|
||||
Функция ставит запрос на прием данных в указанный буфер.
|
||||
Сами данные будут в буфере только по завершению запроса.
|
||||
Для постановки запроса необходимо, чтобы был свободный дескриптор (можно
|
||||
узнать через hdma_recv_req_rdy())
|
||||
|
||||
@param[in] buf Указатель на массив на передачу.
|
||||
@param[in] size Количество 32-битных слов на передачу
|
||||
@return < 0 при ошибке, >= 0 - id передачи при успехе
|
||||
*******************************************************************************/
|
||||
int hdma_recv_req_start(uint32_t* buf, uint32_t size) {
|
||||
if (hdma_recv_req_rdy() > 0) {
|
||||
hdma_set_descr((t_hdma_stream_descr*)g_state.hdma.out, &f_rcv_next_descr, &f_rcv_start_id, buf, size, 0);
|
||||
STREAM_OUT_SET_REQ();
|
||||
return f_rcv_start_id-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Обработчик прерывания на завершения записи в память BF по HDMA
|
||||
|
||||
Обработчик вызывается по завершению приема блока по HostDMA. Обработчик
|
||||
выполняет установку необходимых флагов для разрешения приема следующего блока
|
||||
и, кроме того, проверяет наличие новой команды и завершения передачи или приема
|
||||
блока из потока данных */
|
||||
ISR(hdma_isr) {
|
||||
if ((*pDMA1_IRQ_STATUS & DMA_DONE) != 0) {
|
||||
/* проверяем, не была ли записана команда */
|
||||
if (g_state.cmd.status == L502_BF_CMD_STATUS_REQ) {
|
||||
l502_cmd_set_req();
|
||||
}
|
||||
/* проверяем, не был ли записан результат передачи
|
||||
по HDMA из BF в PC */
|
||||
if (g_state.hdma.in_lb.valid) {
|
||||
/* обновляем id завершенной передачи и вызываем callback */
|
||||
f_snd_done_id = g_state.hdma.in_lb.id;
|
||||
g_state.hdma.in_lb.valid = 0;
|
||||
hdma_send_done(g_state.hdma.in_lb.addr, g_state.hdma.in_lb.udata);
|
||||
}
|
||||
/* проверяем, не был ли записан результат приема данных по
|
||||
HDMA из PC в BF */
|
||||
if (g_state.hdma.out_lb.valid) {
|
||||
/* может быть записан и при не полностью завершенном запросе.
|
||||
определяем сперва резмер, сколько было реально принято */
|
||||
uint32_t size = (g_state.hdma.out[f_rcv_done_descr].full_size -
|
||||
g_state.hdma.out_lb.full_size)/2;
|
||||
|
||||
g_state.hdma.out_lb.valid = 0;
|
||||
|
||||
|
||||
hdma_recv_done(g_state.hdma.out_lb.addr, size);
|
||||
|
||||
/* если была завершена только часть дескриптора -
|
||||
обновляем оставшийся размер для приема */
|
||||
if (g_state.hdma.out_lb.full_size) {
|
||||
g_state.hdma.out[f_rcv_done_descr].full_size =
|
||||
g_state.hdma.out_lb.full_size;
|
||||
} else {
|
||||
/* если завершен весь дескриптор - переходим
|
||||
к следующему */
|
||||
if (++f_rcv_done_descr== L502_OUT_HDMA_DESCR_CNT)
|
||||
f_rcv_done_descr = 0;
|
||||
f_rcv_done_id = g_state.hdma.out_lb.id;
|
||||
}
|
||||
}
|
||||
|
||||
*pDMA1_IRQ_STATUS = DMA_DONE;
|
||||
csync();
|
||||
*pHOST_STATUS = DMA_CMPLT;
|
||||
}
|
||||
ssync();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Обработчик прерывания на завершение чтения по HDMA.
|
||||
|
||||
Данный обработчик вызывается по завершению передачи блока данных по HostDMA.
|
||||
Выполняет только установку необходимых флагов для разрешения следующей
|
||||
передачи */
|
||||
ISR(hdma_rd_isr) {
|
||||
if ((*pHOST_STATUS & HOSTRD_DONE) != 0) {
|
||||
*pHOST_STATUS &= ~((unsigned short)HOSTRD_DONE);
|
||||
*pHOST_STATUS |= DMA_CMPLT;
|
||||
}
|
||||
ssync();
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,44 @@
|
||||
/** @defgroup hdma Ðàáîòà ñ èíòåðôåéñîì HostDMA */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup hdma
|
||||
@{
|
||||
@file l502_hdma.h
|
||||
|
||||
Ôàéë ñîäåðæèò îïèñàíèÿ ôóíêöèé äëÿ ðàáîòû ñ èíòåðôåéñîì HostDMA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L502_HDMA_H_
|
||||
#define L502_HDMA_H_
|
||||
|
||||
|
||||
void hdma_init(void);
|
||||
|
||||
/** Ôëàãè äëÿ ïåðåäà÷è ïî #t_hdma_send_flags */
|
||||
typedef enum {
|
||||
/** Ôëàã, óêàçûâàþùèé, ÷òî ïåðåäàåòñÿ ïîñëåäíèé ïàêåò äàííûõ. Ïî çàâåðøåíèþ
|
||||
ïåðåäà÷è áóäåò îñòàíîâëåí ïîòîê è ñãåíåðèðîâàíî ïðåðûâàíèÿ äëÿ ÏÊ */
|
||||
L502_HDMA_FLAGS_SEND_LAST = 0x1
|
||||
} t_hdma_send_flags;
|
||||
|
||||
|
||||
void hdma_send_start(void);
|
||||
void hdma_send_stop(void);
|
||||
|
||||
|
||||
int hdma_send_req_start(const uint32_t* snd_buf, uint32_t size, uint32_t flags);
|
||||
int hdma_send_req_rdy(void);
|
||||
|
||||
|
||||
void hdma_recv_start(void);
|
||||
|
||||
void hdma_recv_stop(void);
|
||||
|
||||
int hdma_recv_req_start(uint32_t* buf, uint32_t size);
|
||||
|
||||
int hdma_recv_req_rdy(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
#include <cdefBF523.h>
|
||||
#include <ccblkfn.h>
|
||||
#include <bfrom.h>
|
||||
#include <sys/exception.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#include "l502_cdefs.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_hdma.h"
|
||||
|
||||
ISR(isr_sport_dma_rx);
|
||||
ISR(isr_sport_dma_tx);
|
||||
|
||||
|
||||
void l502_stream_init(void);
|
||||
|
||||
/* fVCO = 530 MHZ = (20/2)*53, CDIV=1, SDIV = 4 => SCLK = 132.5 MHz */
|
||||
#define L502_PLL_CTL (SET_MSEL(53) | DF)
|
||||
#define L502_PLL_DIV (SET_SSEL(4) | CSEL_DIV1)
|
||||
|
||||
/* конфигурим SDRAM
|
||||
* RDIV=((117964,8*64ms)/8192)-(6+3)=912 // по логике - это последняя конфигурация
|
||||
* кстати - возможно не 8192, а 4096, в таком случае 1834
|
||||
*/
|
||||
#define L502_SDRAM_SDRRC (((132500000 / 1000) * 64) / 8192 - (6 + 3))
|
||||
/* размер памяти - 32 Мб, 9 бит - под адрес колонки */
|
||||
#define L502_SDRAM_SDBCTL (EBE | EBSZ_32 | EBCAW_9)
|
||||
/* CAS latency=3, хотя можно и 2 - чем меньше тем лучше (правда при этом глюки появляются!!!!)
|
||||
* PASR_ALL - тоже для SDRAM с 2.5 В - экономия энергии, поэтому рефрешим все
|
||||
* tRAS(min)=45 нс (при частоте 120 Мгц - 6 тактов)
|
||||
* tRP(min)=20 нс (при частоте 120 Мгц - 3 тактов)
|
||||
* tRCD(min)=20 нс (при частоте 120 Мгц - 3 тактов)
|
||||
* tWR - хз, на вскидку 2
|
||||
* POWER startup delay - не нужна
|
||||
* PSS - power SDRAM - должно быть
|
||||
* SRFS - нужна для перевода SDRAM в режим пониженного энергопотребления 0 не нужно
|
||||
* EBUFE=0 - только один чип SDRAM
|
||||
* FBBRW=0 - для того, чтобы чтение сразу шло за записью, может не работать - попробовать позже
|
||||
* EMREN=0 - тоже для SDRAM с 2.5 В - экономия энергии
|
||||
* TCSR=0 - тоже для SDRAM с 2.5 В - экономия энергии
|
||||
* CDDBG=0 - по моему сотекщд signals не расшарены
|
||||
*/
|
||||
#define L502_SDRAM_SDGCTL (SCTLE | CL_2 | PASR_ALL | TRAS_6 | TRP_3 | TRCD_3 | TWR_2 | PSS)
|
||||
|
||||
|
||||
uint32_t l502_otp_make_invalid(uint32_t page) {
|
||||
uint32_t err = bfrom_OtpCommand(OTP_INIT, (0x0A548800 | 133));
|
||||
if(!err) {
|
||||
uint64_t val = (uint64_t)3 << OTP_INVALID_P;
|
||||
err = bfrom_OtpWrite(page, OTP_LOWER_HALF | OTP_NO_ECC, &val);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Настройка частоты BlackFin'a */
|
||||
void l502_setup_pll(void) {
|
||||
ADI_SYSCTRL_VALUES sysctl;
|
||||
sysctl.uwPllCtl = L502_PLL_CTL;
|
||||
bfrom_SysControl(SYSCTRL_WRITE | SYSCTRL_PLLCTL, &sysctl, 0);
|
||||
}
|
||||
|
||||
/* Запись настроек PLL и SDRAM в блок OTP, начиная с заданной страницы */
|
||||
uint32_t l502_otp_write_cfg(uint32_t first_page) {
|
||||
uint32_t err = bfrom_OtpCommand(OTP_INIT, (0x0A548800 | 133));
|
||||
uint64_t val = 0;
|
||||
if (!err) {
|
||||
val = ((uint64_t)L502_PLL_DIV << OTP_PLL_DIV_P) | ((uint64_t)L502_PLL_CTL << OTP_PLL_CTL_P)
|
||||
| ((uint64_t)OTP_SET_PLL_M<< 32)| ((uint64_t)OTP_LOAD_PBS02L_M<<32);
|
||||
err = bfrom_OtpWrite(first_page, OTP_LOWER_HALF | OTP_CHECK_FOR_PREV_WRITE, &val);
|
||||
if (!err) {
|
||||
val = ((uint64_t)L502_SDRAM_SDRRC << OTP_EBIU_SDRCC_P) | ((uint64_t)L502_SDRAM_SDBCTL << OTP_EBIU_SDBCTL_P)
|
||||
| ((uint64_t)L502_SDRAM_SDGCTL << OTP_EBIU_SDGCTL_P);
|
||||
err = bfrom_OtpWrite(PBS02-PBS00+first_page, OTP_LOWER_HALF
|
||||
| OTP_CHECK_FOR_PREV_WRITE, &val);
|
||||
}
|
||||
|
||||
/* если была ошибка - делаем недействительным весь блок */
|
||||
if (err)
|
||||
l502_otp_make_invalid(first_page);
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Проверяем, есть ли действтиельные настройки PLL и SDRAM в OTP. Если нет,
|
||||
то записываем их в OTP и инициализируем PLL вручную */
|
||||
void l502_otp_init(void) {
|
||||
uint32_t err=0, page, fnd=0, pll_setup=0;
|
||||
|
||||
//err = l502_otp_make_invalid(PBS00);
|
||||
|
||||
/* ищем первый действительный блок настройки загрузки */
|
||||
for (page = PBS00; !(fnd && !err) && (page < 0xD8); page += 4) {
|
||||
uint64_t val;
|
||||
err = bfrom_OtpRead(page, OTP_LOWER_HALF, &val);
|
||||
if (!err && !((val>>OTP_INVALID_P)&0x3)) {
|
||||
fnd = 1;
|
||||
if (!val) {
|
||||
/* если блок с настройками не был записан => PLL записываем
|
||||
вручную и записываем настройки для корректной инициализации
|
||||
в дальнейшем */
|
||||
if (!pll_setup) {
|
||||
l502_setup_pll();
|
||||
pll_setup = 1;
|
||||
}
|
||||
err = l502_otp_write_cfg(page);
|
||||
page+=4;
|
||||
if (!err && (page< 0xD8)) {
|
||||
/* если есть место - то дописываем вторую копию, чтобы всегда
|
||||
быть уверенным, что если даже при первом чтении была ошибка,
|
||||
все загрузится нормально */
|
||||
err = l502_otp_write_cfg(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* если все страницы настроек испорчены, то инициализируем PLL,
|
||||
так как скорее всего его система не проинициализировала */
|
||||
if (!fnd && !pll_setup) {
|
||||
l502_setup_pll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void l502_init(void) {
|
||||
/* инициализация OTP-памяти и PLL, если эти значения не были уже
|
||||
* проинициализированны до этого. Если в OTP уже были нужные значения, то
|
||||
* SDRAM и PLL проинициализированы уже загрузочным кодом BlackFin */
|
||||
l502_otp_init();
|
||||
|
||||
|
||||
/* настройка SPI */
|
||||
fpga_spi_init();
|
||||
|
||||
/* настройки SPORT0 */
|
||||
*pSPORT0_TCLKDIV = 0;
|
||||
*pSPORT0_RCLKDIV = 0;
|
||||
|
||||
/* clk - internal, fs - external, req, active high, early */
|
||||
*pSPORT0_TCR1 = ITCLK | TFSR; //TCKFE-???
|
||||
*pSPORT0_RCR1 = IRCLK | RFSR | RCKFE;
|
||||
/* len = 16 bit, secondary enable */
|
||||
*pSPORT0_TCR2 = SLEN(15) | TXSE;
|
||||
*pSPORT0_RCR2 = SLEN(15) | RXSE;
|
||||
|
||||
*pPORTF_MUX = (*pPORTF_MUX & 0xFFFC) | 1;
|
||||
*pPORTF_FER |= PF0 | PF1 | PF2 | PF3 | PF4 | PF5 | PF6 | PF7;
|
||||
|
||||
/* назначение SPORT RX на IVG7 */
|
||||
*pSIC_IAR2 = (*pSIC_IAR2 & 0xFFFFFFF0UL) | P16_IVG(7);
|
||||
REGISTER_ISR(7, isr_sport_dma_rx);
|
||||
/* SPORT TX оставляем на IVG9 */
|
||||
REGISTER_ISR(9, isr_sport_dma_tx);
|
||||
|
||||
/* настройка HostDMA-интерфейса */
|
||||
hdma_init();
|
||||
|
||||
|
||||
/* если SDRAM не настроена, то инициализируем ее */
|
||||
if (*pEBIU_SDSTAT & SDRS) {
|
||||
uint32_t* a=0;
|
||||
*pEBIU_SDRRC = L502_SDRAM_SDRRC;
|
||||
*pEBIU_SDBCTL = L502_SDRAM_SDBCTL;
|
||||
*pEBIU_SDGCTL = L502_SDRAM_SDGCTL;
|
||||
ssync();
|
||||
|
||||
*a = 0; /* записываем по нулевому адресу произвольное слово, чтобы активировать память */
|
||||
|
||||
while (*pEBIU_SDSTAT & SDRS) {}
|
||||
}
|
||||
|
||||
/* инициализируем параметры для потоков ввода/вывода */
|
||||
l502_stream_init();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/** @addtogroup config_params
|
||||
@{
|
||||
@file l502_params.c
|
||||
Ôàéë ñîäåðæèò ôóíêöèè ïî îáðàáîòêå êîìàíä îò ÏÊ íà óñòàíîâêó ïàðàìåòðîâ
|
||||
êîíôèãóðàöèè ñáîðà äàííûõ è äðóãèõ ïàðàìåòðîâ.
|
||||
Òîëüêî â äàííîì ôàéëå äîëæíû áûòü èçìåíåíèÿ ïîëåé ñòðóêòóðû îáùèõ
|
||||
íàñòðîåê - g_set.
|
||||
Òàê æå çäåñü */
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "l502_global.h"
|
||||
#include "l502_cmd.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_params.h"
|
||||
#include "l502_stream.h"
|
||||
|
||||
|
||||
|
||||
/* ïðîâåðêà ïðàâèëüíîãî ðåæèìà ñèíõðîíèçàöèè */
|
||||
#define CHECK_SYNC_MODE(cmd) (((cmd) != L502_SYNC_INTERNAL) \
|
||||
&& ((cmd) !=L502_SYNC_EXTERNAL_MASTER) \
|
||||
&& ((cmd) != L502_SYNC_DI_SYN1_RISE) \
|
||||
&& ((cmd) != L502_SYNC_DI_SYN2_RISE) \
|
||||
&& ((cmd) != L502_SYNC_DI_SYN1_FALL) \
|
||||
&& ((cmd) != L502_SYNC_DI_SYN2_FALL) ? L502_BF_ERR_INVALID_CMD_PARAMS : 0)
|
||||
|
||||
|
||||
t_settings g_set = {
|
||||
.lch_cnt = 1,
|
||||
.adc_freq_div = 1,
|
||||
.adc_frame_delay = 0,
|
||||
.din_freq_div = 2,
|
||||
.ref_freq = L502_REF_FREQ_2000KHZ,
|
||||
.out_freq_div = X502_OUT_FREQ_DIV_DEFAULT,
|
||||
.sync_mode = L502_SYNC_INTERNAL,
|
||||
.sync_start_mode = L502_SYNC_INTERNAL
|
||||
};
|
||||
|
||||
t_module_info g_module_info;
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Óñòàíîâêà êîëè÷åñòâà ëîãè÷åñêèõ êàíàëîâ
|
||||
|
||||
Ïðîâåðêà è çàïèñü â ïîëå g_set.lch_cnt çíà÷åíèå êîë-âà êàíàëîâ â ëîãè÷åñêîé
|
||||
òàáëèöå ÀÖÏ.
|
||||
|
||||
@param[in] lch_cnt Êîëè÷åñòâî ëîãè÷åñêèõ êàíàëîâ (îò 1 äî #L502_LTABLE_MAX_CH_CNT)
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_lch_cnt(uint32_t lch_cnt) {
|
||||
if (lch_cnt > L502_LTABLE_MAX_CH_CNT)
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
g_set.lch_cnt = lch_cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Óñòàíîâèòü ïàðàìåòðû ëîãè÷åñêîãî êàíàëà
|
||||
|
||||
Ôóíêöèÿ ïðîâåðÿåò âõîäíûå ïàðàìåòðû è çàïèñûâàåò èõ â ñîîòâåòñòâóþùåå ïîëå
|
||||
òàáëèöû g_set.lch[]
|
||||
|
||||
@param[in] index Íîìåð ëîãè÷åñêîãî êàíàëà [0, L502_LTABLE_MAX_CH_CNT-1]
|
||||
@param[in] ch Íîìåð ôèçè÷åñêîãî êàíàëà (îò 0 äî 15 èëè 31)
|
||||
@param[in] mode Ðåæèì èçìåðåíèÿ äëÿ äàííîãî ëîã. êàíàëà
|
||||
@param[in] range Äèàïàçîí èçìåðåíèÿ äëÿ äàííîãî ëîã. êàíàëà
|
||||
@param[in] avg Êîýô. óñðåäíåíèÿ ïî äàííîìó ëîã. êàíàëó
|
||||
@param[in] flags Äîïîëíèòåëüíûå ôëàãè
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_lch(uint32_t index, uint32_t ch, t_l502_lch_mode mode,
|
||||
t_l502_adc_range range, uint32_t avg, uint32_t flags) {
|
||||
if (index >= L502_LTABLE_MAX_CH_CNT)
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
if ((mode!=L502_LCH_MODE_COMM) && (mode != L502_LCH_MODE_DIFF) &&
|
||||
(mode!=L502_LCH_MODE_ZERO))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
if ((ch >= 32) || ((mode != L502_LCH_MODE_COMM) && (ch>=16)))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
|
||||
|
||||
g_set.lch[index].phy_ch = ch;
|
||||
g_set.lch[index].mode = mode;
|
||||
g_set.lch[index].range = range;
|
||||
g_set.lch[index].avg = avg;
|
||||
g_set.lch[index].flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Óñòàíîâêà äåëèòåëÿ ÷àñòîòû ÀÖÏ
|
||||
@param[in] div Çíà÷åíèå äåëèòåëÿ
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_adc_freq_div(uint32_t div) {
|
||||
if ((div==0) || (div > L502_ADC_FREQ_DIV_MAX))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
g_set.adc_freq_div = div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Óñòàíîâêà çíà÷åíèÿ îïîðíîé ÷àñòîòû
|
||||
@param[in] freq_code Çíà÷åíèå ÷àñòîòû. Äëÿ âíóòðåííåé ìîæåò áûòü òîëüêî
|
||||
#L502_REF_FREQ_2000KHZ èëè #L502_REF_FREQ_1500KHZ
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_ref_freq(uint32_t freq_code) {
|
||||
g_set.ref_freq = freq_code;
|
||||
return 0;
|
||||
}
|
||||
/** Óñòàíîâêà çíà÷åíèÿ ìåæêàäðîâîé çàäåðæêè
|
||||
@param[in] delay Çíà÷åíèå ìåæêàäðîâîé çàäåðæêè (îò 0 äî L502_ADC_INTERFRAME_DELAY_MAX)
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_adc_interframe_delay(uint32_t delay) {
|
||||
if (delay > L502_ADC_INTERFRAME_DELAY_MAX)
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
g_set.adc_frame_delay = delay;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Óñòàíîâêà èñòî÷íèêà îïðîíîé ÷àñòîòû ñèíõðîíèçàöèè
|
||||
@param[in] sync_mode Çíà÷åíèå èç #t_l502_sync_mode
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_sync_mode(t_l502_sync_mode sync_mode) {
|
||||
int32_t err = CHECK_SYNC_MODE(sync_mode);
|
||||
if (!err)
|
||||
g_set.sync_mode = sync_mode;
|
||||
return err;
|
||||
}
|
||||
|
||||
/** Óñòàíîâêà èñòî÷íèêà ñèíõðîíèçàöèè ñòàðòà ñáîðà äàííûõ
|
||||
@param[in] sync_mode Çíà÷åíèå èç #t_l502_sync_mode
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_sync_start_mode(t_l502_sync_mode sync_mode) {
|
||||
int32_t err = CHECK_SYNC_MODE(sync_mode);
|
||||
if (!err)
|
||||
g_set.sync_start_mode = sync_mode;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/** Óñòàíîâêà äåëèòåëÿ ÷àñòîòû ñèíõðîííîãî ââîäà öèôðîâûõ ëèíèé
|
||||
@param[in] div Çíà÷åíèå äåëèòåëÿ
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_din_freq_div(uint32_t div) {
|
||||
if ((div==0) || (div > L502_DIN_FREQ_DIV_MAX))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
g_set.din_freq_div = div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Óñòàíîâêà äåëèòåëÿ ÷àñòîòû âûâîäà íà ÖÀÏ
|
||||
@param[in] div Çíà÷åíèå äåëèòåëÿ (1 èëè 2)
|
||||
@return Êîä îøèáêè */
|
||||
int32_t params_set_dac_freq_div(uint32_t div) {
|
||||
if ((div < X502_OUT_FREQ_DIV_MIN) || (div > X502_OUT_FREQ_DIV_MAX))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
g_set.out_freq_div = div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Çàïèñü ïàðàìåòðîâ ñáîðà â ðåãèñòðû ÏËÈÑ
|
||||
|
||||
Ôóíêöèÿ âûïîëíÿåò çàïèñü âñåõ ïàðàìåòðîâ èç ñòðóêòóðû #g_set â ðåãèñòðû
|
||||
ÏËÈÑ. Ôóíêöèÿ ìîæåò âûçûâàòüñÿ òîëüêî êîãäà ñáîð äàííûõ îñòàíîâëåí.
|
||||
|
||||
@return Êîä îøèáêè */
|
||||
int32_t configure(void) {
|
||||
uint16_t ch;
|
||||
|
||||
int32_t err = g_mode != L502_BF_MODE_IDLE ? L502_BF_ERR_STREAM_RUNNING : 0;
|
||||
if (!err) {
|
||||
/* çàïèñûâàåì ëîãè÷åñêóþ òàáëèöó */
|
||||
for (ch = 0; ch < g_set.lch_cnt; ch++) {
|
||||
uint32_t wrd = ((g_set.lch[ch].phy_ch & 0xF) << 3) | (g_set.lch[ch].range & 0x7);
|
||||
|
||||
if (g_set.lch[ch].mode == L502_LCH_MODE_ZERO) {
|
||||
wrd |= (3 << 7);
|
||||
} else if (g_set.lch[ch].mode == L502_LCH_MODE_COMM) {
|
||||
wrd |= (g_set.lch[ch].phy_ch & 0x10 ? 2 : 1) << 7;
|
||||
}
|
||||
|
||||
if (g_set.lch[ch].avg)
|
||||
wrd |= ((g_set.lch[ch].avg-1) & 0x7F) << 9;
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_LTABLE + g_set.lch_cnt - 1 - ch, wrd);
|
||||
}
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_LCH_CNT, g_set.lch_cnt - 1);
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_ADC_FREQ_DIV, g_set.adc_freq_div - 1);
|
||||
fpga_reg_write(L502_REGS_IOARITH_ADC_FREQ_DIV, g_set.adc_freq_div - 1);
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_ADC_FRAME_DELAY, g_set.adc_frame_delay);
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_IO_MODE, (g_set.sync_mode & 0x7)
|
||||
| ((g_set.sync_start_mode&0x7)<<3)
|
||||
| ((g_set.ref_freq==L502_REF_FREQ_2000KHZ ? 0 : 2) << 7)
|
||||
| (((g_set.out_freq_div-1)&0x3FF)<<9));
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_DIGIN_FREQ_DIV, g_set.din_freq_div - 1);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,79 @@
|
||||
/** @defgroup config_params Íàñòðîéêè ñáîðà äàííûõ ìîäóëÿ */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup config_params
|
||||
@{
|
||||
@file l502_params.h
|
||||
Ôàéë ñîäåðæèò îïðåäåëåíèå ñòðóêòóð, îïèñûâàþùèõ òåêóùèå
|
||||
íàñòðîéêè ñáîðà äàííûõ äëÿ ìîäóëÿ è îáúÿâëÿåò
|
||||
âíåøíþþ ïåðåìåííóþ g_set, ñîäåðæàùóþ ýòè ïàðàìåòðû
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef L502_PARAMS_H_
|
||||
#define L502_PARAMS_H_
|
||||
|
||||
|
||||
#include "l502_defs.h"
|
||||
|
||||
/** Êàëèáðîâî÷íûå êîýôôèöèåíòû ÖÀÏ */
|
||||
typedef struct {
|
||||
float offs; /**< Ñìåùåíèå íóëÿ */
|
||||
float k; /**< Êîýôôèöèåíò øêàëû */
|
||||
} t_dac_cbr_coef;
|
||||
|
||||
/** Èíôîðìàöèÿ î èñïîëüçóåìîì ìîäóëå */
|
||||
typedef struct {
|
||||
uint32_t devflags; /**< Ôëàãè ñ èíôîðìàöèåé î íàëè÷èè îïöèé è ñîñò. ìîäóëÿ */
|
||||
uint16_t fpga_ver; /**< Âåðñèÿ FPGA */
|
||||
uint8_t plda_ver; /**< Âåðñèÿ PLDA */
|
||||
t_dac_cbr_coef dac_cbr[L502_DAC_CH_CNT]; /**< Êîýôôèöèåíòû ÖÀÏ */
|
||||
} t_module_info;
|
||||
|
||||
|
||||
/** Ïàðàìåòðû ëîãè÷åñêîãî êàíàëà */
|
||||
typedef struct {
|
||||
uint8_t phy_ch; /**< Íîìåð ôèçè÷åñêîãî êàíàëà */
|
||||
uint8_t mode; /**< Ðåæèì ñáîðà */
|
||||
uint8_t range; /**< Äèàïàçîí */
|
||||
uint8_t avg; /**< Êîýô. óñðåäíåíèÿ */
|
||||
uint32_t flags; /**< Äîï. ôëàãè */
|
||||
} t_lch;
|
||||
|
||||
|
||||
/** Íàñòðîéêè ñáîðà äàííûõ */
|
||||
typedef struct {
|
||||
/** Òàáëèöà ëîãè÷åñêèõ êàíàëîâ */
|
||||
t_lch lch[L502_LTABLE_MAX_CH_CNT];
|
||||
uint16_t lch_cnt; /**< Êîëè÷åñòâî êàíàëîâ â ëîã. òàáëèöå */
|
||||
uint32_t adc_freq_div; /**< Äåëèòåëü ÷àñòîòû ÀÖÏ */
|
||||
uint32_t din_freq_div; /**< Äåëèòåëü ÷àñòîòû äëÿ öèôðîâîãî âõîäà */
|
||||
uint32_t adc_frame_delay; /**< Ìåæêàäðîâàÿ çàäåðæêà */
|
||||
uint32_t ref_freq; /**< Çíà÷åíèå îïîðíîé ÷àñòîòû (2 èëè 1.5 ÌÃö) èëè âíåøíÿÿ */
|
||||
uint16_t out_freq_div; /**< Äåëèòåëü ÷àñòîòû âûâîäà */
|
||||
uint8_t sync_mode; /**< Ðåæèì ñèíõðîíèçàöèè äëÿ îïîðíîé ÷àñòîòû */
|
||||
uint8_t sync_start_mode; /**< Ðåæèì çàïóñêà ñèãíàëà ñèíõðîíèçàöèè */
|
||||
} t_settings;
|
||||
|
||||
/** Ñòðóêòóðà, ñîäåðæàùàÿ òåêóùèå íàñòðîéêè ñáîðà äàííûõ */
|
||||
extern t_settings g_set;
|
||||
/** Ñòðóêòóðà, ñîäåðæàùàÿ èíôîðìàöèþ î ìîäóëå */
|
||||
extern t_module_info g_module_info;
|
||||
|
||||
int32_t configure(void);
|
||||
|
||||
int32_t params_set_lch_cnt(uint32_t lch_cnt);
|
||||
int32_t params_set_lch(uint32_t index, uint32_t ch, t_l502_lch_mode mode,
|
||||
t_l502_adc_range range, uint32_t avg, uint32_t flags);
|
||||
int32_t params_set_adc_freq_div(uint32_t div);
|
||||
int32_t params_set_adc_interframe_delay(uint32_t delay);
|
||||
int32_t params_set_ref_freq(uint32_t freq_code);
|
||||
int32_t params_set_sync_mode(t_l502_sync_mode sync_mode);
|
||||
int32_t params_set_sync_start_mode(t_l502_sync_mode sync_mode);
|
||||
int32_t params_set_din_freq_div(uint32_t div);
|
||||
int32_t params_set_dac_freq_div(uint32_t div);
|
||||
int32_t params_set_dac_freq_div(uint32_t div);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,23 @@
|
||||
/** @defgroup sport_rx Ïðèåì ïîòîêà äàííûõ ïî SPORT0 */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup sport_rx
|
||||
@{
|
||||
@file l502_sport_rx.h
|
||||
|
||||
Ôàéë ñîäåðæèò îïèñàíèÿ ôóíêöèé äëÿ óïðàâëåíèÿ ïðèåìîì ïîòîêà ïî SPORT0
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L502_SPORT_RX_H
|
||||
#define L502_SPORT_RX_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void sport_rx_start(void);
|
||||
void sport_rx_stop(void);
|
||||
int32_t sport_in_set_step_size(uint32_t size);
|
||||
|
||||
|
||||
#endif // L502_SPORT_RX_H
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,238 @@
|
||||
/** @addtogroup sport_tx
|
||||
@{
|
||||
@file l502_sport_tx.c
|
||||
Файл содержит логику для управления передачей по SPORT0.
|
||||
Изначально DMA должен быть проинициализирован с помощью sport_tx_init(),
|
||||
Передача начинается с помщью sport_tx_start_req(). Можно поставить до 16
|
||||
запросов одновременно.
|
||||
Останвить все текущие передачи можно с помощью sport_tx_stop().
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include <cdefBF523.h>
|
||||
#include <sys/exception.h>
|
||||
#include <ccblkfn.h>
|
||||
#include "l502_sport_tx.h"
|
||||
#include "l502_cdefs.h"
|
||||
#include "l502_fpga_regs.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_bf_cmd_defs.h"
|
||||
#include "l502_defs.h"
|
||||
#include "l502_stream.h"
|
||||
|
||||
#define SPORT_TX_DESCR_CNT 16
|
||||
|
||||
#define SPORT_TX_DMA_CFG_WAIT (DMAEN | DI_EN | WDSIZE_16 | SYNC)
|
||||
#define SPORT_TX_DMA_CFG_START (SPORT_TX_DMA_CFG_WAIT | NDSIZE_5 | FLOW_SMALL)
|
||||
|
||||
|
||||
|
||||
/* дескриптор DMA размера 5 16-битных слов */
|
||||
typedef struct {
|
||||
uint16_t ndpl;
|
||||
uint16_t sal;
|
||||
uint16_t sah;
|
||||
uint16_t cfg;
|
||||
uint16_t xcnt;
|
||||
} t_sport_dma_descr;
|
||||
|
||||
|
||||
static t_sport_dma_descr f_descrs[SPORT_TX_DESCR_CNT];
|
||||
static uint8_t f_put_descr, f_done_descr;
|
||||
static volatile int f_put_cnt, f_done_cnt;
|
||||
static int f_first;
|
||||
|
||||
static volatile int f_tx_was_empty = 0;
|
||||
|
||||
void sport_tx_done(uint32_t* addr, uint32_t size);
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Чтение флагов статуса вывода
|
||||
@return Флаги статуса --- набор битов из #t_x502_out_status_flags,
|
||||
объединенных через логическое “ИЛИ”.
|
||||
******************************************************************************/
|
||||
uint32_t sport_tx_out_status(void) {
|
||||
uint32_t ret = 0;
|
||||
if (f_put_cnt == f_done_cnt)
|
||||
ret |= X502_OUT_STATUS_FLAG_BUF_IS_EMPTY;
|
||||
if (f_tx_was_empty) {
|
||||
ret |= X502_OUT_STATUS_FLAG_BUF_WAS_EMPTY;
|
||||
f_tx_was_empty = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Начальная инициализация канала DMA на передачу по SPORT.
|
||||
|
||||
Функция устанавливает параметры DMA которые не меняются при последующей работе
|
||||
прошивки */
|
||||
void sport_tx_init(void) {
|
||||
int i;
|
||||
for (i=0; i < SPORT_TX_DESCR_CNT; i++) {
|
||||
f_descrs[i].cfg = SPORT_TX_DMA_CFG_WAIT;
|
||||
f_descrs[i].ndpl = i==(SPORT_TX_DESCR_CNT-1) ? (uint32_t)&f_descrs[0]&0xFFFF :
|
||||
(uint32_t)&f_descrs[i+1]&0xFFFF;
|
||||
}
|
||||
|
||||
*pDMA4_NEXT_DESC_PTR = f_descrs;
|
||||
*pDMA4_X_MODIFY = 2;
|
||||
f_put_cnt = f_done_cnt = 0;
|
||||
f_put_descr = f_done_descr = 0;
|
||||
f_first = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Функция разрешает канал DMA для передачи данных в SPORT0 и саму передачу
|
||||
* для SPORT 0 */
|
||||
static void f_sport_tx_start(void) {
|
||||
/* разрешаем передачу по SPORT'у */
|
||||
*pSPORT0_TCR1 |= TSPEN;
|
||||
f_first = 0;
|
||||
f_tx_was_empty = 0;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Останов сбора по SPORT0.
|
||||
*
|
||||
* Функция запрещает прием по SPORT0 и соответствующий канал DMA на прем */
|
||||
void sport_tx_stop(void) {
|
||||
*pSIC_IMASK0 &= ~IRQ_DMA4;
|
||||
|
||||
*pDMA4_CONFIG = 0;
|
||||
/* нужно подождать до 3-х циклов, чтобы DMA действительно завершился */
|
||||
ssync();
|
||||
ssync();
|
||||
ssync();
|
||||
/* запрет передачи по SPORT */
|
||||
*pSPORT0_TCR1 &= ~TSPEN;
|
||||
/* сбрасываем признаки прерываний от DMA */
|
||||
*pDMA4_IRQ_STATUS = DMA_DONE | DMA_ERR;
|
||||
|
||||
/* заново инициализируем все дескрипторы */
|
||||
sport_tx_init();
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Получить количество свободных дескрипторов на передачу
|
||||
|
||||
Функция возвращает количество запросов, которое можно поставить в очередь
|
||||
на передачу с помощью sport_tx_start_req().
|
||||
@return Количество запросов на передачу, которое можно поставить в очередь
|
||||
******************************************************************************/
|
||||
int sport_tx_req_rdy(void) {
|
||||
return SPORT_TX_DESCR_CNT - (f_put_cnt - f_done_cnt + 1);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
@brief Поставить запрос на передачу по SPORT0
|
||||
|
||||
Функция ставит запрос на передачу указанных данных. Сами данные не копируются,
|
||||
т.е. буфер нельзя будет использовать до того, как данные не будут переданы!
|
||||
Для постановки запроса необходимо, чтобы был свободный дескриптор (можно
|
||||
узнать через sport_tx_req_rdy()).
|
||||
|
||||
Количество слов в запросе не должно превышать #SPORT_TX_REQ_SIZE_MAX
|
||||
|
||||
При добавление первого дескриптора автомтически разрешается передача по
|
||||
DMA и SPORT0.
|
||||
|
||||
@param[in] buf Указатель на массив на передачу.
|
||||
@param[in] size Количество 32-битных слов на передачу
|
||||
*******************************************************************************/
|
||||
void sport_tx_start_req(uint32_t* buf, uint32_t size) {
|
||||
/* запрещаем прерывание от DMA на случай гонок с изменением позиций */
|
||||
*pSIC_IMASK0 &= ~IRQ_DMA4;
|
||||
|
||||
f_descrs[f_put_descr].sal = (uint32_t)buf & 0xFFFF;
|
||||
f_descrs[f_put_descr].sah = ((uint32_t)buf >> 16) & 0xFFFF;
|
||||
f_descrs[f_put_descr].xcnt = size*2;
|
||||
f_descrs[f_put_descr].cfg = SPORT_TX_DMA_CFG_WAIT;
|
||||
/* убеждаемся, что данные будут уже записаны в память к моменту запуска DMA */
|
||||
ssync();
|
||||
|
||||
/* если DMA сейчас остановлен => запускаем его */
|
||||
if (f_put_cnt==f_done_cnt) {
|
||||
uint32_t cfg_wrd = SPORT_TX_DMA_CFG_START;
|
||||
*pDMA4_CONFIG = cfg_wrd;
|
||||
if (f_first)
|
||||
f_sport_tx_start();
|
||||
}
|
||||
|
||||
if (f_put_cnt!=f_done_cnt) {
|
||||
uint8_t prev_descr = (f_put_descr==0) ? SPORT_TX_DESCR_CNT-1 : f_put_descr-1;
|
||||
f_descrs[prev_descr].cfg = SPORT_TX_DMA_CFG_START;
|
||||
}
|
||||
|
||||
if (++f_put_descr==SPORT_TX_DESCR_CNT)
|
||||
f_put_descr=0;
|
||||
f_put_cnt++;
|
||||
|
||||
*pSIC_IMASK0 |= IRQ_DMA4;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Обработчик прерывания по SPORT0 на завершение передачи.
|
||||
|
||||
Прерывание возникает, когда был передан блок данных по SPORT0, соответствующий
|
||||
одному дескриптору.
|
||||
Функция рассчитывает количество переданных данных и вызывает sport_tx_done().
|
||||
Также функция помечает дескриптор как свободный и при необходимости
|
||||
снова запускает DMA (если он был остановлен, но при этом уже добавлен новый
|
||||
дескриптор на передачу) */
|
||||
ISR( isr_sport_dma_tx) {
|
||||
if (*pDMA4_IRQ_STATUS & DMA_DONE) {
|
||||
uint32_t* addr;
|
||||
uint32_t size;
|
||||
uint32_t status;
|
||||
|
||||
*pDMA4_IRQ_STATUS = DMA_DONE;
|
||||
|
||||
/* обработку выполняем только в случае, если есть начатые, но не завершенные
|
||||
дескрипторы */
|
||||
if (f_done_cnt != f_put_cnt) {
|
||||
f_done_cnt++;
|
||||
|
||||
f_descrs[f_done_descr].cfg = SPORT_TX_DMA_CFG_WAIT;
|
||||
|
||||
addr = ((uint32_t*)(f_descrs[f_done_descr].sal |
|
||||
((uint32_t)f_descrs[f_done_descr].sah<<16)) + f_descrs[f_done_descr].xcnt*2);
|
||||
size = f_descrs[f_done_descr].xcnt/2;
|
||||
if (!size)
|
||||
size = 0x8000;
|
||||
sport_tx_done(addr, size);
|
||||
|
||||
if (++f_done_descr==SPORT_TX_DESCR_CNT)
|
||||
f_done_descr=0;
|
||||
|
||||
ssync();
|
||||
|
||||
status = *pDMA4_IRQ_STATUS;
|
||||
/* если DMA остановлен, а дескрипторы на передачу еще есть => запускаем снова */
|
||||
if ((f_done_cnt != f_put_cnt) && !(status & DMA_RUN)) {
|
||||
*pDMA4_CONFIG = SPORT_TX_DMA_CFG_START;
|
||||
}
|
||||
|
||||
if (f_done_cnt == f_put_cnt) {
|
||||
ssync();
|
||||
}
|
||||
|
||||
if ((g_stream_out_state == OUT_STREAM_RUN) && (f_done_cnt == f_put_cnt))
|
||||
f_tx_was_empty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*pDMA4_IRQ_STATUS & DMA_ERR) {
|
||||
*pDMA4_IRQ_STATUS = DMA_ERR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,28 @@
|
||||
/** @defgroup sport_tx Ïåðåäà÷à ïîòîêà äàííûõ ïî SPORT0 */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup sport_tx
|
||||
@{
|
||||
@file l502_sport_tx.h
|
||||
|
||||
Ôàéë ñîäåðæèò îïèñàíèÿ ôóíêöèé äëÿ óïðàâëåíèÿ ïåðåäà÷è ïîòîêà ïî SPORT0
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L502_SPORT_TX_H
|
||||
#define L502_SPORT_TX_H
|
||||
|
||||
/** Ìàêñèìàëüíûé ðàçìåð ïðè ïåðåäà÷å â ôóíêöèþ sport_tx_start_req() */
|
||||
#define SPORT_TX_REQ_SIZE_MAX (16*1024)
|
||||
|
||||
void sport_tx_init(void);
|
||||
void sport_tx_stop(void);
|
||||
int sport_tx_req_rdy(void);
|
||||
|
||||
|
||||
void sport_tx_start_req(uint32_t* addr, uint32_t size);
|
||||
|
||||
uint32_t sport_tx_out_status(void);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,570 @@
|
||||
/**
|
||||
@addtogroup streams
|
||||
@{
|
||||
|
||||
@file l502_stream.c
|
||||
Файл содержит функции обработки потоков от АЦП/DIN в ПК и от ПК в ЦАП/DOUT.
|
||||
Также в этот файл внесена реализация функций приема по SPORT0, так как они
|
||||
связаны с логикой управления потоков.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cdefBF523.h>
|
||||
#include <sys/exception.h>
|
||||
#include <ccblkfn.h>
|
||||
|
||||
#include "l502_cdefs.h"
|
||||
#include "l502_cmd.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_defs.h"
|
||||
#include "l502_global.h"
|
||||
#include "l502_hdma.h"
|
||||
#include "l502_sport_tx.h"
|
||||
#include "l502_user_process.h"
|
||||
#include "l502_stream.h"
|
||||
#include "l502_sport_rx.h"
|
||||
|
||||
|
||||
/** Размер буфера на прием данных по SPORT0 в 32-битных словах */
|
||||
#define L502_SPORT_IN_BUF_SIZE (2048*1024)
|
||||
/** Размер буфера для приема данных по HostDMA на вывод в 32-битных словах */
|
||||
#define L502_HDMA_OUT_BUF_SIZE (1024*1024)
|
||||
|
||||
/** Шаг прерываний для приема данных по SPORT0 по-умолчанию */
|
||||
#define L502_DEFAULT_SPORT_RX_BLOCK_SIZE (32*1024)
|
||||
|
||||
|
||||
|
||||
|
||||
t_in_stream_state g_stream_in_state = IN_STREAM_STOP;
|
||||
t_out_stream_state g_stream_out_state = OUT_STREAM_STOP;
|
||||
/** Режим работы - определяет, запущен ли синхронный сбор или тест */
|
||||
volatile int g_mode = L502_BF_MODE_IDLE;
|
||||
|
||||
int g_streams = L502_STREAM_ADC;
|
||||
static int f_bf_reg = 0;
|
||||
|
||||
/* слово, обозначающее, что произошло переполнение */
|
||||
static const uint32_t f_overflow_wrd = L502_STREAM_IN_MSG_OVERFLOW;
|
||||
|
||||
|
||||
|
||||
/* буфер для приема digin и данных АЦП от SPORT (в неинициализируемой области) */
|
||||
#include "l502_sdram_noinit.h"
|
||||
static volatile uint32_t f_sport_in_buf[L502_SPORT_IN_BUF_SIZE];
|
||||
/* позиция в буфере в которую будет записан следующий принятых отсчет */
|
||||
static volatile uint32_t f_sport_in_put_pos = 0;
|
||||
/* позиция в буфере за последним обработанным отсчетом */
|
||||
static uint32_t f_sport_in_proc_pos = 0;
|
||||
/* позиция в буфере за последним изятым из буфера отсчетом (позиция первого занятого отсчета) */
|
||||
static volatile uint32_t f_sport_in_get_pos = 0;
|
||||
/* шаг прерываний на прием по SPORT0 */
|
||||
static uint32_t f_sport_in_block_size = L502_DEFAULT_SPORT_RX_BLOCK_SIZE;
|
||||
/* реально используемый размер входного буфера на прием */
|
||||
static uint32_t f_sport_in_buf_size = L502_SPORT_IN_BUF_SIZE;
|
||||
|
||||
|
||||
/* буфер для прв кинятых данных по HDMA для вывода на ЦАП и DIGOUT */
|
||||
#include "l502_sdram_noinit.h"
|
||||
static volatile uint32_t f_hdma_out_buf[L502_HDMA_OUT_BUF_SIZE];
|
||||
static volatile uint32_t f_hdma_out_put_pos = 0; /* указатель на позицию за последним принятым по HDMA */
|
||||
static uint32_t f_hdma_out_start_pos; /* указатель на позицию за последним поставленным на прием словом
|
||||
(с нее будет стартовать следующий запрос) */
|
||||
static volatile uint32_t f_hdma_out_get_pos = 0; /* указатель на позицию за последним обработанным словом
|
||||
(с нее будет взято следующее слово для обработки, когда будет готово */
|
||||
static int f_hdma_out_block_size = 0x8000;
|
||||
static int f_hdma_out_proc_pos;
|
||||
|
||||
static uint32_t f_recv_size = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* функция вызывается при возникновении переполнения буфера на прием
|
||||
по SPORT'у данных АЦП/DIGIN */
|
||||
static void f_stream_in_set_overflow(void) {
|
||||
/* останавливаем прием данных от АЦП */
|
||||
sport_rx_stop();
|
||||
/* устанавливаем флаг, что нужно передать сообщение о
|
||||
переполнении */
|
||||
g_stream_in_state = IN_STREAM_OV_ALERT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Начальная инициализация параметров для синхронных потоков */
|
||||
void l502_stream_init(void) {
|
||||
/* останавливаем сбор данных, если он был запущен */
|
||||
fpga_reg_write(L502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, 0);
|
||||
/* настройка DMA на передачу по SPORT */
|
||||
sport_tx_init();
|
||||
}
|
||||
|
||||
|
||||
/** @brief Запуск предзагрузки данных на вывода
|
||||
|
||||
Данная функция запускает предзагрузку данных потока на вывод.
|
||||
Используется, чтобы загрузить данные в буфер BlackFin до запуска синхронного
|
||||
ввода-вывода.
|
||||
@return Код ошибки */
|
||||
int32_t stream_out_preload(void) {
|
||||
int32_t err = g_stream_out_state==OUT_STREAM_RUN ? L502_BF_ERR_STREAM_RUNNING :
|
||||
0;
|
||||
if (!err) {
|
||||
f_hdma_out_get_pos = f_hdma_out_start_pos =
|
||||
f_hdma_out_put_pos = f_hdma_out_proc_pos = 0;
|
||||
|
||||
/* разрешаем прием по HDMA */
|
||||
hdma_recv_start();
|
||||
/* запускаем первый блок на прием (остальные будут
|
||||
добавлены из stream_proc() */
|
||||
f_hdma_out_start_pos+=f_hdma_out_block_size;
|
||||
hdma_recv_req_start((uint32_t*)f_hdma_out_buf, f_hdma_out_block_size);
|
||||
|
||||
g_stream_out_state = OUT_STREAM_PRELOAD;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void f_set_streams(uint32_t streams) {
|
||||
uint32_t wrd_en = 0;
|
||||
|
||||
/* если уже запущен потоковый режим и разрешается один из
|
||||
потоков на ввод, то инициализируем прием по SPORT и передачу по hdma */
|
||||
if (g_mode == L502_BF_MODE_STREAM) {
|
||||
if ((streams & L502_STREAM_ALL_IN) && !(g_streams & L502_STREAM_ALL_IN)) {
|
||||
sport_rx_start();
|
||||
}
|
||||
|
||||
if (!(streams & L502_STREAM_ALL_IN) && (g_streams & L502_STREAM_ALL_IN)) {
|
||||
sport_rx_stop();
|
||||
}
|
||||
}
|
||||
|
||||
/* изменяем разрешенные потоки в регистре FPGA */
|
||||
if (streams & L502_STREAM_ADC)
|
||||
wrd_en |= 0x1;
|
||||
if (streams & L502_STREAM_DIN)
|
||||
wrd_en |= 0x2;
|
||||
fpga_reg_write(L502_REGS_IOARITH_IN_STREAM_ENABLE, wrd_en);
|
||||
|
||||
|
||||
/** @todo: разрешение на лету выходных потоков */
|
||||
|
||||
g_streams = streams;
|
||||
}
|
||||
|
||||
/** @brief Разрешение указанных синхронных потоков
|
||||
@param[in] streams Битовая маска из #t_l502_streams, указывающая какие потоки
|
||||
должны быть разрешены (в дополнения к уже разрешенным)
|
||||
@return Код ошибки */
|
||||
int32_t stream_enable(uint32_t streams) {
|
||||
f_set_streams(g_streams | streams);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Запрещение указанных синхронных потоков
|
||||
@param[in] streams Битовая маска из #t_l502_streams, указывающая какие потоки
|
||||
должны быть запрещены
|
||||
@return Код ошибки */
|
||||
int32_t stream_disable(uint32_t streams) {
|
||||
f_set_streams(g_streams & ~streams);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Запуск синхронного ввода-вывода
|
||||
|
||||
Функция запускает синхронный ввод-вывод платы.
|
||||
При этом начинается передача по всем ранее разрешенным потокам с помощью
|
||||
stream_enable().
|
||||
После вызова этой функции изменять настройки модуля уже нельязя, однако
|
||||
можно дополнительно разрешать или запрещать потоки через stream_enable()
|
||||
или stream_disable().
|
||||
|
||||
@return Код ошибки.
|
||||
***************************************************************************/
|
||||
int32_t streams_start(void) {
|
||||
int32_t err = g_mode != L502_BF_MODE_IDLE ? L502_BF_ERR_STREAM_RUNNING : 0;
|
||||
if (!err) {
|
||||
/* прием по SPORT инициализируется всесте с началом запуска
|
||||
синхронного сбора */
|
||||
f_sport_in_put_pos = f_sport_in_get_pos = f_sport_in_proc_pos = 0;
|
||||
|
||||
|
||||
if (g_streams & L502_STREAM_ALL_IN) {
|
||||
sport_rx_start();
|
||||
g_stream_in_state = IN_STREAM_RUN;
|
||||
}
|
||||
|
||||
hdma_send_start();
|
||||
|
||||
f_set_streams(g_streams);
|
||||
|
||||
if (g_streams & L502_STREAM_ALL_OUT) {
|
||||
/* разрешаем ПЛИС генерацию TFS по SPORT */
|
||||
f_bf_reg |= L502_REGBIT_IOHARD_OUT_TFS_EN_Msk;
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, f_bf_reg);
|
||||
|
||||
|
||||
/* если не было предзагрузки до запуска,
|
||||
то запускаем прием сейчас */
|
||||
if ((g_stream_out_state == OUT_STREAM_STOP) ||
|
||||
(g_stream_out_state == OUT_STREAM_ERR)) {
|
||||
stream_out_preload();
|
||||
}
|
||||
|
||||
if (g_stream_out_state == OUT_STREAM_PRELOAD) {
|
||||
/* выполняем предзагрузку данных */
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, f_bf_reg | 1);
|
||||
g_stream_out_state = OUT_STREAM_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Так как конвейер автомата управления входной коммутации АЦП состоит
|
||||
из 2-х стадий, для корректного синхронного старта необходимо в
|
||||
ыполнить два раза предзагрузку. В противном случае,
|
||||
время момента первого отсчета может не совпадать с моментом
|
||||
запуска синхронизации
|
||||
*/
|
||||
fpga_reg_write(L502_REGS_IOHARD_PRELOAD_ADC, 1);
|
||||
fpga_reg_write(L502_REGS_IOHARD_PRELOAD_ADC, 1);
|
||||
|
||||
|
||||
fpga_reg_write(L502_REGS_IOHARD_GO_SYNC_IO, 1);
|
||||
|
||||
g_mode = L502_BF_MODE_STREAM;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Останов синхронных потоков ввода-вывода.
|
||||
|
||||
По этой функции останавливаются все синхронные потоки.
|
||||
Запрещается передача потоков по SPORT и по HostDMA
|
||||
|
||||
@return Код ошибки */
|
||||
int32_t streams_stop(void) {
|
||||
int32_t err = g_mode != L502_BF_MODE_STREAM ? L502_BF_ERR_STREAM_STOPPED : 0;
|
||||
if (!err) {
|
||||
hdma_send_stop();
|
||||
hdma_recv_stop();
|
||||
fpga_reg_write(L502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
|
||||
/* запрещаем прием и передачу по SPORT'у */
|
||||
sport_rx_stop();
|
||||
sport_tx_stop();
|
||||
|
||||
/* запрещаем генерацию TFS и RFS */
|
||||
f_bf_reg = 0;
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, f_bf_reg);
|
||||
|
||||
|
||||
g_mode = L502_BF_MODE_IDLE;
|
||||
g_stream_in_state = IN_STREAM_STOP;
|
||||
g_stream_out_state = OUT_STREAM_STOP;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Фоновая обработка потокой ввода-вывода
|
||||
|
||||
Функция переодически вызывается из основного цикла программы.
|
||||
При рабочем режиме, проверяются, есть
|
||||
ли необработанные данные пришедшие от АЦП/DIGIN и/или пришедшие от ПК данные
|
||||
на ЦАП или DOUT. При их наличии вызывается соответствующая функция пользовательской
|
||||
обработки данных.
|
||||
Также, если было переполнение и все данные до переполнения были обработаны,
|
||||
то в ПК посылается слово о том, что в этом месте произошло переполнение */
|
||||
void stream_proc(void) {
|
||||
/* если запущен поток ввода */
|
||||
if ((g_stream_in_state != IN_STREAM_STOP) && (g_stream_in_state != IN_STREAM_ERR)) {
|
||||
uint32_t sport_rdy_size;
|
||||
uint32_t put_pos = f_sport_in_put_pos;
|
||||
|
||||
/* смотрим, сколько принято необработанных данных по sport'у */
|
||||
sport_rdy_size = put_pos >= f_sport_in_proc_pos ?
|
||||
put_pos - f_sport_in_proc_pos : f_sport_in_buf_size - f_sport_in_proc_pos;
|
||||
/* если есть необработанные данные - вызываем функцию для обработки */
|
||||
if (sport_rdy_size) {
|
||||
uint32_t processed = usr_in_proc_data(
|
||||
(uint32_t*)&f_sport_in_buf[f_sport_in_proc_pos],
|
||||
sport_rdy_size);
|
||||
/* обновляем счетчик обработканных данных */
|
||||
f_sport_in_proc_pos += processed;
|
||||
if (f_sport_in_proc_pos==f_sport_in_buf_size)
|
||||
f_sport_in_proc_pos = 0;
|
||||
}
|
||||
|
||||
/* если было переполнение - нужно передать слово о переполнениии.
|
||||
передаем его после того, как передадим все слова до переполнения */
|
||||
if ((g_stream_in_state == IN_STREAM_OV_ALERT) && !sport_rdy_size && hdma_send_req_rdy()) {
|
||||
hdma_send_req_start(&f_overflow_wrd, 1, 1);
|
||||
g_stream_in_state = IN_STREAM_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* если есть поток на вывод */
|
||||
if ((g_stream_out_state == OUT_STREAM_PRELOAD) ||
|
||||
(g_stream_out_state == OUT_STREAM_RUN)) {
|
||||
|
||||
uint32_t hdma_rdy_size;
|
||||
uint32_t put_pos = f_hdma_out_put_pos;
|
||||
|
||||
/* проверяем, сколько есть необработанных данных, принятых по HDMA */
|
||||
hdma_rdy_size = put_pos >= f_hdma_out_proc_pos ?
|
||||
put_pos - f_hdma_out_proc_pos : L502_HDMA_OUT_BUF_SIZE - f_hdma_out_proc_pos;
|
||||
|
||||
|
||||
/* если такие есть -> пробуем обработать */
|
||||
if (hdma_rdy_size != 0) {
|
||||
uint32_t processed = usr_out_proc_data(
|
||||
(uint32_t*)&f_hdma_out_buf[f_hdma_out_proc_pos],
|
||||
hdma_rdy_size);
|
||||
|
||||
/* обновляем счетчик обработанных данных */
|
||||
f_hdma_out_proc_pos += processed;
|
||||
if (f_hdma_out_proc_pos==L502_HDMA_OUT_BUF_SIZE)
|
||||
f_hdma_out_proc_pos = 0;
|
||||
}
|
||||
|
||||
|
||||
/* если есть свободное место в буфере на прием и есть свободные
|
||||
дескрипторы => ставим новый запрос на прием даннх */
|
||||
if (hdma_recv_req_rdy()) {
|
||||
uint32_t get_pos = f_hdma_out_get_pos;
|
||||
|
||||
hdma_rdy_size = f_hdma_out_start_pos >= get_pos ?
|
||||
L502_HDMA_OUT_BUF_SIZE - f_hdma_out_start_pos + get_pos :
|
||||
get_pos - f_hdma_out_start_pos;
|
||||
if (hdma_rdy_size > f_hdma_out_block_size) {
|
||||
hdma_recv_req_start((uint32_t*)&f_hdma_out_buf[f_hdma_out_start_pos],
|
||||
f_hdma_out_block_size);
|
||||
|
||||
f_hdma_out_start_pos+=f_hdma_out_block_size;
|
||||
if (f_hdma_out_start_pos==L502_HDMA_OUT_BUF_SIZE)
|
||||
f_hdma_out_start_pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Освобождение size слов из буфера приема по SPORT0
|
||||
|
||||
Функция помечает, что size слов из начала той части буфера SPORT0, в которую
|
||||
были приняты данные, но не освобождены, как освобожденные. Т.е. в эту область
|
||||
снова можно будет принимать данные со SPORT0.
|
||||
При этом надо всегда следить, чтобы количество освобожденных данных не
|
||||
привышало количество обработанных!
|
||||
|
||||
@param[in] size Размер освобожденных данных в 32-битных словах */
|
||||
void stream_in_buf_free(uint32_t size) {
|
||||
/* обновляем позицию переданного слова */
|
||||
uint32_t get_pos = f_sport_in_get_pos;
|
||||
get_pos += size;
|
||||
if (get_pos >= f_sport_in_buf_size)
|
||||
get_pos-= f_sport_in_buf_size;
|
||||
f_sport_in_get_pos = get_pos;
|
||||
}
|
||||
|
||||
/** @brief Освобождение size слов из буфера приема по HostDMA
|
||||
|
||||
Функция помечает, что size слов из начала той части буфера HostDMA, в которую
|
||||
были приняты данные от ПК, но не освобождены, как освобожденные. Т.е. в эту область
|
||||
снова можно будет принимать данные от ПК по HostDMA.
|
||||
При этом надо всегда следить, чтобы количество освобожденных данных не
|
||||
привышало количество обработанных!
|
||||
|
||||
@param[in] size Размер освобожденных данных в 32-битных словах */
|
||||
void stream_out_buf_free(uint32_t size) {
|
||||
uint32_t get_pos = f_hdma_out_get_pos;
|
||||
get_pos += size;
|
||||
if (get_pos >= L502_HDMA_OUT_BUF_SIZE)
|
||||
get_pos -= L502_HDMA_OUT_BUF_SIZE;
|
||||
f_hdma_out_get_pos = get_pos;
|
||||
}
|
||||
|
||||
/** @brief Обработка завершения приема по HostDMA
|
||||
|
||||
Функция вызывается из обработчика прерывания, когда завершился прием
|
||||
блока данных по HDMA в ПК, поставленного до этого на передачу с
|
||||
помощью hdma_recv_req_start().
|
||||
Функция просто обновляет счетчик принятых данных (а обработка будет уже
|
||||
из фоновой функции stream_proc().
|
||||
|
||||
@param[in] addr Адрес слова, сразу за последним принятым словом.
|
||||
@param[in] size Количество принятых 32-битных слов */
|
||||
void hdma_recv_done(uint32_t* addr, uint32_t size) {
|
||||
/* обновляем позицию принятого слова */
|
||||
uint32_t put_pos = f_hdma_out_put_pos;
|
||||
put_pos += size;
|
||||
if (put_pos == L502_HDMA_OUT_BUF_SIZE)
|
||||
put_pos = 0;
|
||||
f_hdma_out_put_pos = put_pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Размер буфера на прием.
|
||||
|
||||
Функция возвращает размер буфера на прием по SPORT0
|
||||
@return размер буфера на прием в 32-битных словах */
|
||||
extern uint32_t sport_in_buffer_size(void) {
|
||||
return L502_SPORT_IN_BUF_SIZE;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @addtogroup sport_rx
|
||||
@{ */
|
||||
|
||||
/** @brief Установка шага прерывания для према по SPORT0
|
||||
|
||||
Функция устанавливает шаг прерываний для DMA, использующегося для
|
||||
приема данных синхронного ввода.
|
||||
При этом размер шага должен быть как имнимум в 4 раза меньше размера
|
||||
буфера #L502_SPORT_IN_BUF_SIZE.
|
||||
После установки шага определяется реально используемый размер буфера,
|
||||
как наибольшее число кратное шагу и не превышающее #L502_SPORT_IN_BUF_SIZE.
|
||||
|
||||
@param[in] size Размер шага прерывания в 32-битных словах
|
||||
@return Код ошибки */
|
||||
int32_t sport_in_set_step_size(uint32_t size) {
|
||||
int mul;
|
||||
if ((size >= L502_SPORT_IN_BUF_SIZE/4) || (size > 0x8000))
|
||||
return L502_BF_ERR_INVALID_CMD_PARAMS;
|
||||
mul = L502_SPORT_IN_BUF_SIZE/size;
|
||||
/* не может быть боьше 0x8000 шагов, так как регистр
|
||||
YCNT 16-разрядный (+ еще умножаем на 2) */
|
||||
if (mul > 0x8000)
|
||||
mul = 0x8000;
|
||||
f_sport_in_buf_size = size*mul;
|
||||
f_sport_in_block_size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Запуск сбора данных по SPORT0
|
||||
|
||||
Функция настраивает DMA3 на режим автобуфера с 2D, размер шага выбирается
|
||||
равным f_sport_in_block_size. После чего разрешается канал DMA и
|
||||
прием по SPORT0 */
|
||||
void sport_rx_start(void) {
|
||||
static volatile int dummy;
|
||||
/* запрещаем DMA */
|
||||
*pDMA3_CONFIG = 0;
|
||||
ssync();
|
||||
/* вычитываем все данные из буфера, если они были */
|
||||
while (*pSPORT0_STAT & RXNE) {
|
||||
dummy = *pSPORT0_RX16;
|
||||
ssync();
|
||||
}
|
||||
|
||||
/* настраиваем DMA */
|
||||
*pDMA3_START_ADDR = (void*)f_sport_in_buf;
|
||||
*pDMA3_X_COUNT = 2*f_sport_in_block_size; /* так как SPORT настроен на 16 бит (хоть и 2 канала),
|
||||
а размер в 32 битных словах => умножаем на 2) */
|
||||
*pDMA3_X_MODIFY = 2;
|
||||
*pDMA3_Y_COUNT = f_sport_in_buf_size/f_sport_in_block_size;;
|
||||
*pDMA3_Y_MODIFY = 2;
|
||||
*pDMA3_CURR_ADDR = (void*)f_sport_in_buf;
|
||||
*pDMA3_CONFIG = FLOW_AUTO | DI_EN | DI_SEL | SYNC | DMA2D | WNR | WDSIZE_16;
|
||||
|
||||
|
||||
ssync();
|
||||
/* разрешаем DMA */
|
||||
*pSIC_IMASK0 |= IRQ_DMA3;
|
||||
*pDMA3_CONFIG |= DMAEN;
|
||||
/* разрешаем прием по SPORT'у */
|
||||
*pSPORT0_RCR1 |= RSPEN;
|
||||
|
||||
/* разрешаем генерацию RFS на SPORT0 */
|
||||
f_bf_reg |= L502_REGBIT_IOHARD_OUT_RFS_EN_Msk;
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, f_bf_reg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Останов сбора данных по SPORT0
|
||||
|
||||
Функция запрещает прием по SPORT0 и останавливает DMA */
|
||||
void sport_rx_stop(void) {
|
||||
/* останавливаем генерацию RFS */
|
||||
f_bf_reg &= ~L502_REGBIT_IOHARD_OUT_RFS_EN_Msk;
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, f_bf_reg);
|
||||
|
||||
ssync();
|
||||
ssync();
|
||||
|
||||
/* запрещаем прием по SPORT */
|
||||
*pSPORT0_RCR1 &= ~RSPEN;
|
||||
/* запрещаем DMA */
|
||||
*pDMA3_CONFIG =0; //&= ~DMAEN;
|
||||
*pSIC_IMASK0 &= ~IRQ_DMA3;
|
||||
//ssync();
|
||||
}
|
||||
|
||||
/** @brief Обработчик прерывания по SPORT0 на прием.
|
||||
|
||||
Прерывание возникает, когда был принят блок данных по SPORT0.
|
||||
Обновляем указатель принятых данных и проверяем переполнение */
|
||||
ISR(isr_sport_dma_rx) {
|
||||
if (*pDMA3_IRQ_STATUS & DMA_DONE) {
|
||||
uint32_t rdy_put_pos;
|
||||
/* сбрасываем прерывание от DMA */
|
||||
*pDMA3_IRQ_STATUS = DMA_DONE;
|
||||
|
||||
/* обновляем количество принятых данных на размер блока */
|
||||
f_sport_in_put_pos += f_sport_in_block_size;
|
||||
if (f_sport_in_put_pos == f_sport_in_buf_size)
|
||||
f_sport_in_put_pos = 0;
|
||||
|
||||
/* смотрим, сколько свободно места в буфере на прием */
|
||||
uint32_t get_pos = f_sport_in_get_pos;
|
||||
rdy_put_pos = f_sport_in_put_pos > get_pos ?
|
||||
f_sport_in_buf_size -f_sport_in_put_pos + get_pos :
|
||||
get_pos - f_sport_in_put_pos;
|
||||
|
||||
|
||||
f_recv_size += f_sport_in_block_size;
|
||||
|
||||
/* если осталось не больше блока - то считаем за переполнение,
|
||||
т.к. тогда при следующем прерывании уже могут быть испорчены
|
||||
принятые ранее данные */
|
||||
if (rdy_put_pos < 2*f_sport_in_block_size) {
|
||||
f_stream_in_set_overflow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/** @defgroup streams Управление потоками сбора данных */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup streams
|
||||
@{
|
||||
@file l502_stream.h
|
||||
|
||||
Файл содержит описания функций для работы с интерфейсом HostDMA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L502_STREAM_H_
|
||||
#define L502_STREAM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Состояние потока на ввод */
|
||||
typedef enum {
|
||||
IN_STREAM_STOP = 0, /**< Поток на ввод остановлен */
|
||||
IN_STREAM_RUN = 2, /**< Поток на ввод в рабочем режиме */
|
||||
IN_STREAM_OV_ALERT = 4, /**< Произошло переполнение - нужно сообщить о ошибке */
|
||||
IN_STREAM_ERR= 3 /**< Поток остановлен из-за ошибки/переполнения */
|
||||
} t_in_stream_state;
|
||||
|
||||
/** Состояние потока на вывод */
|
||||
typedef enum {
|
||||
OUT_STREAM_STOP = 0, /**< Поток на вывод остановлен */
|
||||
OUT_STREAM_PRELOAD = 1, /**< Идет предзагрузка данных - данные принимаются
|
||||
от ПК, но еще не запущен синхронных сбор/выдача */
|
||||
OUT_STREAM_RUN = 2, /** Поток запущен на выдачу */
|
||||
OUT_STREAM_ERR = 3, /** Поток остановлен по ошибке (сейчас не используется) */
|
||||
OUT_STREAM_CYCLE = 4 /** Режим циклического буфера (сейчас не реализован) */
|
||||
} t_out_stream_state;
|
||||
|
||||
|
||||
/** Состояние потока на ввод */
|
||||
extern t_in_stream_state g_stream_in_state;
|
||||
/** Состояние потока на вывод */
|
||||
extern t_out_stream_state g_stream_out_state;
|
||||
/** Режим работы прошивки из #t_l502_bf_mode */
|
||||
extern volatile int g_mode;
|
||||
/** Флаги, обозначающие какие потоки разрешены */
|
||||
extern int g_streams;
|
||||
|
||||
|
||||
int32_t streams_start(void);
|
||||
int32_t streams_stop(void);
|
||||
|
||||
int32_t stream_enable(uint32_t streams);
|
||||
int32_t stream_disable(uint32_t streams);
|
||||
|
||||
int32_t stream_out_preload(void);
|
||||
|
||||
|
||||
void stream_in_buf_free(uint32_t size);
|
||||
void stream_out_buf_free(uint32_t size);
|
||||
|
||||
|
||||
uint32_t sport_in_buffer_size(void);
|
||||
int32_t sport_in_set_step_size(uint32_t size);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,421 @@
|
||||
/** @file l502_test.c
|
||||
Äàííûé ôàéë ñîäåðæèò ðåàëèçàöèþ òåñòîâ àïïàðàòóðû.
|
||||
Ýòè òåñòû èñïîëüçóåòñÿ ïðè íàëàäêå ïðèáîðà è íå âûïîëíÿåòñÿ â øòàòíîì ðåæèìå ðàáîòû,
|
||||
îäíàêî âêëþ÷åíèå èõ â ïðîøèâêó ïîçâîëÿåò âûïîëíÿòü ïðîâåðêó è ïîñëå ýòàïà íàëàäêè
|
||||
(îäíàêî íå âî âðåìÿ ñáîðà äàííûõ è ò.ï.)
|
||||
|
||||
Äëÿ óïðàâëåíèÿ òåñòàìè ïðåäíàçíà÷åíà ñïåöèàëüíàÿ êîìàíäà îò PC ê BlackFin: L502_BF_CMD_CODE_TEST.
|
||||
Ïàðàìåòð ýòîé êàîìàíäû îïðåäåëÿåò äåéñòâèå:
|
||||
- çàïóñòèòü òåñò ñ çàäàííûì íîìåðîì
|
||||
- îñòàíîâèòü òåêóùèé òåñò
|
||||
- ïîëó÷èòü ðåçóëüòàòû âûïîëíÿåìîãî â äàííûõ ìîìåíò òåñòà èëè
|
||||
ïîñëåäíåãî âûïîëíÿåìîãî òåñòà (åñëè òåñò îñòàíîâëåí).
|
||||
|
||||
Ïî êàêîãî-ëèáî òåñòà ìîäóëü ïåðåõîäèò â åòñòîâûé ðåæèì (èçìåíÿåòñÿ g_mode)
|
||||
è âûïîëíÿåò ôóíêöèþ, ñîîòâåòñòâóþùóþ çàäàííîìó òåñòó (èç ýòîé ôóíêöèè òåñò
|
||||
äîëæåí ïåðåîäè÷åñêè ïðîâåðÿòü ïðèõîä äðóãèõ êîìàíä îò PC).
|
||||
Òåñò âûïîëíÿåòñÿ ëèáî äî îøèáêè, ëèáî äî ïðèõîäà êîìàíäû îñòàíîâà).
|
||||
Óçíàòü ðåçóëüòàò òåñòà ìîæíî êîìàíäîé ñ ïàðàìåòðîì L502_BF_CMD_TEST_GET_RESULT.
|
||||
|
||||
Äîñòóïíû ñëåäóþùèå òåñòû:
|
||||
- Ïðîâåðêà SDRAM
|
||||
- Ïðîâåðêà SPI
|
||||
- Ïðîâåðêà SPORT
|
||||
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cdefBF523.h>
|
||||
#include <sys/exception.h>
|
||||
|
||||
#include "l502_cmd.h"
|
||||
#include "l502_fpga.h"
|
||||
#include "l502_sport_tx.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
extern int g_mode;
|
||||
|
||||
/* ìîäóëü ñ÷åò÷èêà, èñïîëüçóåìîãî äëÿ òåñòîâ SDRAM è SPORT */
|
||||
#define L502_TEST_CNTR_MODULE 35317
|
||||
|
||||
/* ðàçìåð îäíîãî áàíêà SDRAM */
|
||||
#define SDRAM_BANK_SIZE (4UL*1024*1024*2)
|
||||
|
||||
/* àäðåñà áàíêîâ SDRAM */
|
||||
static volatile uint16_t* bank1 = NULL;
|
||||
static volatile uint16_t* bank2 = (uint16_t*)(SDRAM_BANK_SIZE);
|
||||
static volatile uint16_t* bank3 = (uint16_t*)(2*SDRAM_BANK_SIZE);
|
||||
static volatile uint16_t* bank4 = (uint16_t*)(3*SDRAM_BANK_SIZE);
|
||||
|
||||
|
||||
#define SPORT_TEST_START_ADDR 0xFF900000
|
||||
#define SPORT_TEST_BUF_SIZE 4096
|
||||
|
||||
/* ðåçóëüòàò ïîñëåäíåãî òåñòà */
|
||||
static t_l502_bf_test_res f_test_res;
|
||||
/* íîìåð ïîñëåäíåãî âûïîëíÿåìîãî òåñòà */
|
||||
static int32_t f_cur_test_ind = -1;
|
||||
|
||||
/* îáúÿâëåíèå ôóíêöèé çàïóñêà òåñòîâ */
|
||||
static int f_sdram_test(void);
|
||||
static int f_spi_test(void);
|
||||
static int f_sport_test(void);
|
||||
|
||||
|
||||
/* ñòðêóòóðà, îïèñûâàþùàÿ ñîîòâåòñòâèÿ êîäà òåñòà è ôóíêöèé òåñòà */
|
||||
typedef struct {
|
||||
uint32_t test_code;
|
||||
int (*start)(void);
|
||||
void (*get_result)(t_l502_bf_cmd *cmd);
|
||||
} t_test_pars;
|
||||
/* òåáëèöà ñîîòâåòñòâèé ôóíêöèé è êîäîâ òåñòîâ */
|
||||
static t_test_pars f_test_pars[] = {
|
||||
{ L502_BF_CMD_TEST_ECHO, NULL, NULL},
|
||||
{ L502_BF_CMD_TEST_SPORT, f_sport_test, NULL},
|
||||
{ L502_BF_CMD_TEST_SDRAM, f_sdram_test, NULL},
|
||||
{ L502_BF_CMD_TEST_SPI, f_spi_test, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void l502_cmd_test(t_l502_bf_cmd *cmd) {
|
||||
/* ïîëó÷åíèå ðåçóëüòàòà òåñòà */
|
||||
if (cmd->param == L502_BF_CMD_TEST_GET_RESULT) {
|
||||
/* åñëè íå áûëî íèêàêîãî òåñòà - âîçâðàùàåì îøèáêó */
|
||||
if (f_cur_test_ind == -1) {
|
||||
l502_cmd_done(L502_BF_ERR_INVALID_CMD_PARAMS, NULL, 0);
|
||||
} else {
|
||||
f_test_res.run = (g_mode == L502_BF_MODE_TEST) ? 1 : 0;
|
||||
|
||||
|
||||
if (f_test_pars[f_cur_test_ind].get_result != NULL) {
|
||||
/* åñëè åñòü ó òåñòà ñïåö ôóíêöèÿ äëÿ ïîëó÷åíèÿ ðåçóëüòàòà =>
|
||||
âûçûâàåì åå */
|
||||
f_test_pars[f_cur_test_ind].get_result(cmd);
|
||||
} else {
|
||||
/* èíà÷å ïðîñòî óñòàíàâëèâàåì ðåçóëüàòàò áåç äàííûõ */
|
||||
l502_cmd_done(0, (uint32_t*)&f_test_res,
|
||||
sizeof(t_l502_bf_test_res)/sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
} else if (cmd->param == L502_BF_CMD_TEST_STOP) {
|
||||
/* îñòàíîâ òåñòà => åñëè òåñò çàïóùåí - âîçâðàùàåì åãî ðåçóëüòàò,
|
||||
èíà÷å âîçâðàùàåì îøèáêó ÷òî è òàê òåñòà íåòó */
|
||||
if (g_mode == L502_BF_MODE_TEST) {
|
||||
g_mode = L502_BF_MODE_IDLE;
|
||||
l502_cmd_done(0, NULL, 0);
|
||||
} else {
|
||||
l502_cmd_done(L502_BF_ERR_NO_TEST_IN_PROGR, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
/* çàïóñê òåñòà - ïðîõîäèì ïî òàáëèöå è èùåì íóæíûé òåñò */
|
||||
if (g_mode == L502_BF_MODE_IDLE) {
|
||||
uint32_t i;
|
||||
|
||||
for (i=0, f_cur_test_ind=-1; (i<sizeof(f_test_pars)/sizeof(f_test_pars[0])) &&
|
||||
(f_cur_test_ind==-1); i++) {
|
||||
if (f_test_pars[i].test_code == cmd->param) {
|
||||
f_cur_test_ind = i;
|
||||
memset(&f_test_res, 0, sizeof(f_test_res));
|
||||
f_test_res.test = cmd->param;
|
||||
l502_cmd_done(0, 0, NULL);
|
||||
|
||||
if (f_test_pars[i].start != NULL) {
|
||||
g_mode = L502_BF_MODE_TEST;
|
||||
f_test_pars[i].start();
|
||||
g_mode = L502_BF_MODE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (f_cur_test_ind == -1)
|
||||
l502_cmd_done(L502_BF_ERR_INVALID_CMD_PARAMS, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
l502_cmd_done(L502_BF_ERR_STREAM_RUNNING, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define SPORT_CNTR_INC 0x1
|
||||
|
||||
|
||||
#define TEST_CHECK_OUT(label) \
|
||||
do { \
|
||||
l502_cmd_check_req(); \
|
||||
if ((g_mode!= L502_BF_MODE_TEST) || f_test_res.err) \
|
||||
goto label; \
|
||||
} while (0);
|
||||
|
||||
|
||||
/* òåñòèðîâàíèå SPORT'à, ñëóæàùåãî äëÿ ïåðåäà÷è ïîòîêîâ ÀÖÏ/ÖÀÏ
|
||||
îò BlackFin'à ê ÏËÈÑ. Óñòàíàâëèâàåòñÿ öèêëè÷åñêèé ñêâîçíîé ðåæèì ïîòîêà
|
||||
è ïåðåäàåòñÿ ñ÷åò÷èê, êîòîðûé ïðîâåðÿåòñÿ ïðè ïðèåìå */
|
||||
static int f_sport_test(void) {
|
||||
#define RX_BUF_SIZE 2048
|
||||
static uint16_t rx_buf[RX_BUF_SIZE];
|
||||
uint16_t stat=*pSPORT0_STAT;
|
||||
|
||||
|
||||
uint16_t rx_cntr=0, tx_cntr=0;
|
||||
uint16_t rx_val;
|
||||
int err = 0, i;
|
||||
|
||||
/* ðàçðåøàåì ïðèåì è ïåðåäà÷ó ïî SPORT'ó */
|
||||
*pSPORT0_TCR1 |= TSPEN;
|
||||
*pSPORT0_RCR1 |= RSPEN;
|
||||
|
||||
while (stat & RXNE) {
|
||||
rx_buf[0] = *pSPORT0_RX16;
|
||||
stat=*pSPORT0_STAT;
|
||||
}
|
||||
|
||||
/* âíà÷àëå ïîëíîñòüþ çàïîëíÿåì î÷åðåäü SPORT'à */
|
||||
for (i = 0; i < 8; i++) {
|
||||
*pSPORT0_TX16 = tx_cntr++;
|
||||
//tx_cntr+=SPORT_CNTR_INC;
|
||||
}
|
||||
|
||||
/* óñòàíàâëèâàåì â ÏËÈÑ ñêâîçíîé ðåæèì ðàáîòû SPORT */
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, 0xE);
|
||||
|
||||
|
||||
while (!f_test_res.err) {// && (g_mode==L502_BF_MODE_TEST))
|
||||
stat = *pSPORT0_STAT;
|
||||
if (!(stat & TXF)) {
|
||||
*pSPORT0_TX16 = tx_cntr++;
|
||||
}
|
||||
|
||||
if (stat & RXNE) {
|
||||
rx_val = *pSPORT0_RX16;
|
||||
|
||||
if ((rx_val != rx_cntr)) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_rd = rx_val;
|
||||
f_test_res.last_wr = rx_cntr;
|
||||
err = rx_val - rx_cntr;
|
||||
}
|
||||
|
||||
|
||||
if (!(rx_cntr & 0xFFFF)) {
|
||||
TEST_CHECK_OUT(sport_test_end);
|
||||
if (!rx_cntr)
|
||||
f_test_res.cntr++;
|
||||
}
|
||||
rx_cntr++;
|
||||
}
|
||||
}
|
||||
|
||||
sport_test_end:
|
||||
/* çàïðåùàåì ïðèåì è ïåðåäà÷ó ïî SPORT'ó */
|
||||
*pSPORT0_TCR1 = 0;
|
||||
*pSPORT0_RCR1 = 0;
|
||||
/* âîçâðàùàåì øòàòíûé ðåæèì ðàáîòû SPORT'à */
|
||||
fpga_reg_write(L502_REGS_IOHARD_OUTSWAP_BFCTL, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* òåñò SPI - çàïèñûâàåì áåãóùóþ åäèíèöó â ðåãèñòð ÏËÈÑ, ñ÷èòûâàåì
|
||||
çíà÷åíèå ýòîãî ðåãèñòðà è ñâåðÿåì ðåçóëüòàòû */
|
||||
static int f_spi_test(void) {
|
||||
f_test_res.last_addr = L502_REGS_IOHARD_ADC_FRAME_DELAY;
|
||||
while (!f_test_res.err && (g_mode==L502_BF_MODE_TEST)) {
|
||||
int i;
|
||||
for (i = 0; (i < 32) && !f_test_res.err; i++) {
|
||||
f_test_res.last_wr = (1<<i);
|
||||
fpga_reg_write(f_test_res.last_addr, f_test_res.last_wr);
|
||||
f_test_res.last_rd = fpga_reg_read(f_test_res.last_addr);
|
||||
|
||||
if (f_test_res.last_wr != f_test_res.last_rd)
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
}
|
||||
|
||||
if (!f_test_res.err)
|
||||
f_test_res.cntr++;
|
||||
|
||||
l502_cmd_check_req();
|
||||
}
|
||||
return f_test_res.err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* òåñò SDRAM ïàìÿòè */
|
||||
static int f_sdram_test(void) {
|
||||
int i;
|
||||
unsigned short cntr = 0;
|
||||
|
||||
|
||||
|
||||
while (!f_test_res.err && (g_mode == L502_BF_MODE_TEST)) {
|
||||
f_test_res.stage = 0;
|
||||
|
||||
/* çàïîëíÿåì âñþ ïàìÿòü ñ÷åò÷èêîì */
|
||||
for (i = 0, cntr = 0; i < (16UL*1024*1024); i++) {
|
||||
bank1[i] = cntr;
|
||||
if (++cntr == L502_TEST_CNTR_MODULE) {
|
||||
cntr = 0;
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
|
||||
|
||||
/* ÷èòàåì ïîñëåäîâàòåëüíî è ñâåðÿåì ðåçóëüòàò */
|
||||
for (i = 0, cntr = 0; i < (16UL*1024*1024); i++) {
|
||||
uint16_t word = bank1[i];
|
||||
if (word != cntr) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank1[i];
|
||||
f_test_res.last_wr = cntr;
|
||||
f_test_res.last_rd = word;
|
||||
break;
|
||||
}
|
||||
|
||||
if (++cntr==L502_TEST_CNTR_MODULE) {
|
||||
cntr = 0;
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
f_test_res.stage++;
|
||||
|
||||
|
||||
/* çàïèñûâàåì ïî ñëîâó â êàæäûé áàíê äëÿ ïðîâåðêè ïåðåêðåñòíîé
|
||||
çàïèñè ïî ðàçíûì áàíêàì */
|
||||
for (i = 0, cntr = 0; i < (4UL*1024*1024); i++) {
|
||||
bank1[i] = cntr;
|
||||
bank2[i] = ~cntr;
|
||||
bank3[i] = cntr^0xAA55;
|
||||
bank4[i] = cntr^0x55AA;
|
||||
if (++cntr == L502_TEST_CNTR_MODULE) {
|
||||
cntr = 0;
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
|
||||
|
||||
for (i = 0, cntr = 0; i < (4UL*1024*1024); i++) {
|
||||
uint16_t word = bank1[i];
|
||||
if (word != cntr) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank1[i];
|
||||
f_test_res.last_wr = cntr;
|
||||
f_test_res.last_rd = word;
|
||||
break;
|
||||
}
|
||||
|
||||
word = bank2[i];
|
||||
if (word != (~cntr & 0xFFFF)) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank2[i];
|
||||
f_test_res.last_wr = (~cntr & 0xFFFF);
|
||||
f_test_res.last_rd = word;
|
||||
break;
|
||||
}
|
||||
word = bank3[i];
|
||||
if (word != ((cntr^0xAA55) & 0xFFFF)) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank3[i];
|
||||
f_test_res.last_wr = ((cntr^0xAA55) & 0xFFFF);
|
||||
f_test_res.last_rd = word;
|
||||
break;
|
||||
}
|
||||
|
||||
word = bank4[i];
|
||||
if (word != ((cntr^0x55AA) & 0xFFFF)) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank4[i];
|
||||
f_test_res.last_wr = ((cntr^0x55AA) & 0xFFFF);
|
||||
f_test_res.last_rd = word;
|
||||
break;
|
||||
}
|
||||
|
||||
if (++cntr == L502_TEST_CNTR_MODULE) {
|
||||
cntr = 0;
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
|
||||
/* çàïèñü â 4 ðàçíûõ áàíêà ñ ïîñëåäóþùèì ÷òåíèåì */
|
||||
f_test_res.stage++;
|
||||
|
||||
for (i = 0, cntr=0; i < (4UL*1024*1024); i++) {
|
||||
uint16_t word[4], wr_val[4] = {~cntr, cntr, cntr^0x55AA, cntr^0xAA55};
|
||||
|
||||
bank1[i] = wr_val[0];
|
||||
bank2[i] = wr_val[1];
|
||||
bank3[i] = wr_val[2];
|
||||
bank4[i] = wr_val[3];
|
||||
|
||||
word[1] = bank2[i];
|
||||
word[0] = bank1[i];
|
||||
word[3] = bank4[i];
|
||||
word[2] = bank3[i];
|
||||
|
||||
|
||||
if (word[0] != wr_val[0]) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank1[i];
|
||||
f_test_res.last_wr = wr_val[0];
|
||||
f_test_res.last_rd = word[0];
|
||||
break;
|
||||
}
|
||||
if (word[1] != wr_val[1]) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank2[i];
|
||||
f_test_res.last_wr = wr_val[1];
|
||||
f_test_res.last_rd = word[1];
|
||||
break;
|
||||
}
|
||||
if (word[2] != wr_val[2]) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank3[i];
|
||||
f_test_res.last_wr = wr_val[2];
|
||||
f_test_res.last_rd = word[2];
|
||||
break;
|
||||
}
|
||||
if (word[3] != wr_val[3]) {
|
||||
f_test_res.err = L502_BF_ERR_TEST_VALUE;
|
||||
f_test_res.last_addr = (uint32_t)&bank4[i];
|
||||
f_test_res.last_wr = wr_val[3];
|
||||
f_test_res.last_rd = word[3];
|
||||
break;
|
||||
}
|
||||
|
||||
if (++cntr == L502_TEST_CNTR_MODULE) {
|
||||
cntr = 0;
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
}
|
||||
}
|
||||
TEST_CHECK_OUT(sdram_test_end);
|
||||
|
||||
f_test_res.cntr++;
|
||||
}
|
||||
sdram_test_end:
|
||||
|
||||
return f_test_res.err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/***************************************************************************//**
|
||||
@addtogroup user_process
|
||||
@{
|
||||
@file l502_user_process.c
|
||||
|
||||
Файл содержит простейший вариант реализации пользовательских функций, в котором
|
||||
потоки данных передаются без изменения и никакие пользовательские команды не
|
||||
обрабатываются. Пользователь может изменить этот файл и добавить здесь свою
|
||||
обработку.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "l502_stream.h"
|
||||
#include "l502_hdma.h"
|
||||
#include "l502_sport_tx.h"
|
||||
#include "l502_cmd.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Обработка принятого массива данных АЦП/DIN.
|
||||
|
||||
Функция вызывается каждый раз, когда обнаружены новые данные от
|
||||
АЦП/цифровых входов, пришедшие по SPORT0.
|
||||
|
||||
Функция должна обработать данные и вернуть количество обработанных данных,
|
||||
однако эти данные все еще считаются использованными (не могут быть переписаны
|
||||
новыми пришедшими данными) до тех пор пока не будет вызвана функция
|
||||
stream_in_buf_free()).
|
||||
|
||||
Если функция вернет значение меньше чем size, то функция будут вызванна при
|
||||
следующем проходе еще раз с указателем на необработанные данные.
|
||||
|
||||
В текущей реализации просто запускается передача данных по HDMA в ПК
|
||||
|
||||
@param[in] data Указатель на массив с принятыми данными
|
||||
@param[in] size Количество принятых данных в 32-битных словах
|
||||
@return Функция возвращает количество обработанных данных (от 0 до size).
|
||||
На эти данные не будет вызываться повторно usr_in_proc_data(),
|
||||
но они считаются еще используемыми
|
||||
*******************************************************************************/
|
||||
uint32_t usr_in_proc_data(uint32_t* data, uint32_t size) {
|
||||
/* если есть свободные дескрипторы на передачу по HDMA - ставим блок на
|
||||
передачу. Иначе возвращаем 0, чтобы на обработку этих данных функцию
|
||||
вызвали бы позже */
|
||||
if (hdma_send_req_rdy()) {
|
||||
hdma_send_req_start(data, size, 0);
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Обработка принятого массива с данными ЦАП/DOUT
|
||||
|
||||
Функция вызывается каждый раз, когда обнаружены новые данные, принятые от
|
||||
ПК по HDMA.
|
||||
Функция должна обработать данные и вернуть количество обработанных данных,
|
||||
однако эти данные все еще считаются использованными (не могут быть переписаны
|
||||
новыми пришедшими данными) до тех пор пока не будет вызвана функция
|
||||
stream_out_buf_free()).
|
||||
|
||||
Если функция вернет значение меньше чем size, то функция будут
|
||||
вызвана после еще раз с указателем на необработанные данные.
|
||||
|
||||
В текущей реализации просто запускается передача данных по SPORT
|
||||
для вывода на ЦАП/цифровые выходы.
|
||||
|
||||
@param[in] data Указатель на массив с принятыми данными
|
||||
@param[in] size Количество принятых данных в 32-битных словах
|
||||
@return Функция возвращает количество обработанных данных (от 0 до size).
|
||||
На эти данные не будет вызываться повторно usr_out_proc_data(),
|
||||
но они считаются еще используемыми
|
||||
******************************************************************************/
|
||||
uint32_t usr_out_proc_data(uint32_t* data, uint32_t size) {
|
||||
|
||||
/* если есть свободные дескрипторы на передачу по HDMA - ставим блок на
|
||||
передачу. Иначе возвращаем 0, чтобы на обработку этих данных функцию
|
||||
вызвали бы позже */
|
||||
if (sport_tx_req_rdy()) {
|
||||
|
||||
/* за один раз можем передать в SPORT не более
|
||||
SPORT_TX_REQ_SIZE_MAX слов */
|
||||
if (size > SPORT_TX_REQ_SIZE_MAX)
|
||||
size = SPORT_TX_REQ_SIZE_MAX;
|
||||
|
||||
sport_tx_start_req(data, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
@brief Обработка завершения передачи по HostDMA
|
||||
|
||||
Функция вызывается из обработчика прерывания, когда завершилась передача
|
||||
блока данных по HDMA в ПК, поставленного до этого на передачу с
|
||||
помощью hdma_send_req_start().
|
||||
|
||||
@param[in] addr Адрес слова, сразу за последним переданным словом
|
||||
@param[in] size Размер переданных данных в 32-битных словах
|
||||
****************************************************************************/
|
||||
void hdma_send_done(uint32_t* addr, uint32_t size) {
|
||||
stream_in_buf_free(size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
@brief Обработка завершения передачи по SPORT
|
||||
|
||||
Функция вызывается из обработчика прерывания при завершении передачи блока данных
|
||||
по SPORT'у на цифровые выходы/ЦАП, поставленного до этого на передачу с
|
||||
помощью sport_tx_start_req().
|
||||
|
||||
|
||||
@param[in] addr Адрес слова, сразу за последним переданным словом
|
||||
@param[in] size Размер переданных данных в 32-битных словах */
|
||||
void sport_tx_done(uint32_t* addr, uint32_t size) {
|
||||
stream_out_buf_free(size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
@brief Обработка пользовательских команд.
|
||||
|
||||
Функция вызывается при приеме команды от ПК с кодом большим или равным
|
||||
#L502_BF_CMD_CODE_USER.
|
||||
|
||||
По завершению обработки необходимо обязательно вызвать
|
||||
l502_cmd_done(), указав код завершения команды и
|
||||
при необходимости передать данные с результатом
|
||||
|
||||
@param[in] cmd Структура с описанием принятой команды
|
||||
******************************************************************************/
|
||||
void usr_cmd_process(t_l502_bf_cmd *cmd) {
|
||||
l502_cmd_done(L502_BF_ERR_UNSUP_CMD, NULL, 0);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/** @defgroup user_process Пользовательская обработка данных */
|
||||
|
||||
/***************************************************************************//**
|
||||
@addtogroup user_process
|
||||
@{
|
||||
@file l502_user_process.h
|
||||
|
||||
Файл содержит описания функций, которые предназначены для изменения
|
||||
пользователем для написания своих алгоритмов обработки данных и реализации
|
||||
пользовательских команд.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef L502_USER_PROCESS_H_
|
||||
#define L502_USER_PROCESS_H_
|
||||
|
||||
|
||||
uint32_t usr_in_proc_data(uint32_t* data, uint32_t size);
|
||||
uint32_t usr_out_proc_data(uint32_t* data, uint32_t size);
|
||||
|
||||
void usr_cmd_process(t_l502_bf_cmd *cmd);
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*****************************************************************************
|
||||
* NewProject.c
|
||||
*****************************************************************************/
|
||||
|
||||
#include "l502_cdefs.h"
|
||||
void l502_init(void);
|
||||
#include "l502_global.h"
|
||||
#include "l502_cmd.h"
|
||||
|
||||
void stream_proc(void);
|
||||
|
||||
/* g_state îïèñûâàåò îáëàñòü ïàìÿòè, ðàñïîëîæåííóþ ïî ôèêñèðîâàííûì àäðåñàì.
|
||||
* Äëÿ ðàñïîëîæåíèÿ â íà÷àëî áàíêà A äàííûõ èñïîëüçóåì ñïåöèàëüíóþ ñåêöèþ */
|
||||
SECTION("board_state", volatile t_l502_board_state g_state);
|
||||
|
||||
|
||||
int main(void) {
|
||||
/* Èíèöèàëèçàöèÿ èíòåðôåéñîâ */
|
||||
l502_init();
|
||||
|
||||
for (;;) {
|
||||
/* ïðîâåðÿåì íàëè÷èå êîìàíäû îò ÏÊ è íà÷èíàÿåì
|
||||
îáðàáîòêó, åñëè îíà åñòü */
|
||||
l502_cmd_check_req();
|
||||
/* îáðàáîòêà ïîòîêîâ äàííûõ */
|
||||
stream_proc();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user