git init of an empty project

This commit is contained in:
2025-06-27 15:12:44 +03:00
commit c73ead2643
76 changed files with 45689 additions and 0 deletions
+43
View File
@@ -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;
}
/** @} */
+46
View File
@@ -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
/** @} */
+167
View File
@@ -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
+44
View File
@@ -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
View File
@@ -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);
}
/** @} */
+71
View File
@@ -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
View File
@@ -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
/** @} */
+69
View File
@@ -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;
}
/** @} */
+31
View File
@@ -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
/** @} */
+208
View File
@@ -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
+77
View File
@@ -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
View File
@@ -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();
}
/** @} */
+44
View File
@@ -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
View File
@@ -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();
}
+208
View File
@@ -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;
}
/** @} */
+79
View File
@@ -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
/** @} */
+23
View File
@@ -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
/** @} */
+238
View File
@@ -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;
}
}
/** @} */
+28
View File
@@ -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
/** @} */
+570
View File
@@ -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();
}
}
}
/** @} */
+65
View File
@@ -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
/** @} */
+421
View File
@@ -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;
}
+162
View File
@@ -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);
}
/** @} */
+26
View File
@@ -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
View File
@@ -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;
}