Files
E502_ADC_BF_PC_companion/lib/x502/x502api_bf.c

392 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "x502api_private.h"
#include "ltimer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BF_LDR_HDR_SIZE (16)
#define BF_LDR_HDRSGN (0xAD)
#define BF_LDR_HDRPOS_SGN (3)
#define BF_LDR_FLAG_SAVE (0x0010) //не используется
#define BF_LDR_FLAG_AUX (0x0020) //не используется
#define BF_LDR_FLAG_FILL (0x0100)
#define BF_LDR_FLAG_QUICKBOOT (0x0200) //не используется
#define BF_LDR_FLAG_CALLBACK (0x0400) //не используется
#define BF_LDR_FLAG_INIT (0x0800) //не используется
#define BF_LDR_FLAG_IGNORE (0x1000)
#define BF_LDR_FLAG_INDIRECT (0x2000) //не используется
#define BF_LDR_FLAG_FIRST (0x4000)
#define BF_LDR_FLAG_FINAL (0x8000)
#define BF_WAIT_LOAD_RDY_TOUT 500
#define BF_MUTEX_LOCK_TOUT 1000
#define LDR_BUFF_SIZE 4096
#define BF_CHECK_ADDR(addr) (((addr) < 0xFFA0C000) && ((addr)>= 0xFFA0000)) || \
(((addr) < 0xFF908000) && ((addr) >=0xFF900000)) || \
(((addr) < 0xFF808000) && ((addr) >=0xFF800000)) || \
(((addr) < 0x2000000)) ? 0 : X502_ERR_BF_INVALID_ADDR
#define BF_CHECK_ADDR_SIZE(addr, size) BF_CHECK_ADDR(addr) ? X502_ERR_BF_INVALID_ADDR : \
BF_CHECK_ADDR(addr+size*4-1) ? X502_ERR_BF_INVALID_ADDR : 0
#define BF_CMD_FIRST_DATA_BLOCK_SIZE ((X502_BF_REQ_DATA_SIZE_MAX-offsetof(t_l502_bf_cmd, data))/4)
typedef struct st_bf_ldr_pkt {
uint8_t res;
uint8_t dma_mode;
uint16_t flags;
uint32_t addr;
uint32_t size;
uint32_t arg;
} t_bf_ldr_pkt;
/* Разбираем заголовок блока LDR-формата из буфера размером BF_LDR_HDR_SIZE
и сохраняем параметры в структуре pkt */
int f_parse_ldr_hdr(const uint8_t* hdr, t_bf_ldr_pkt* pkt) {
int err = 0;
uint32_t* pdw_buff = (uint32_t*)hdr;
uint8_t xor_ch = 0;
int i;
for (i=0; i < BF_LDR_HDR_SIZE; i++) {
xor_ch ^= hdr[i];
}
if ((xor_ch!=0) || (hdr[BF_LDR_HDRPOS_SGN] != BF_LDR_HDRSGN)) {
err = X502_ERR_LDR_FILE_FORMAT;
} else {
pkt->res = 0;
pkt->dma_mode = pdw_buff[0]&0xF;
pkt->flags = pdw_buff[0]&0xFFF0;
pkt->addr = pdw_buff[1];
pkt->size = pdw_buff[2];
pkt->arg = pdw_buff[3];
if ((pkt->flags & BF_LDR_FLAG_INIT) && (pkt->flags & BF_LDR_FLAG_FILL))
err = X502_ERR_LDR_FILE_FORMAT;
else if (pkt->flags & (BF_LDR_FLAG_CALLBACK | BF_LDR_FLAG_INDIRECT | BF_LDR_FLAG_INIT))
err = X502_ERR_LDR_FILE_UNSUP_FEATURE;
else if ((pkt->flags & BF_LDR_FLAG_INIT) && (pkt->addr != 0xFFA00000))
err = X502_ERR_LDR_FILE_UNSUP_STARTUP_ADDR;
}
return err;
}
static int32_t f_bf_mem_wr(t_x502_hnd hnd, uint32_t addr, const uint32_t* regs, uint32_t size) {
int32_t err = 0;
/* данные записываем блоками по L502_BF_REQ_DATA_SIZE */
while (!err && size) {
int put_size = (size < hnd->iface_hnd->bf_mem_block_size) ? size :
hnd->iface_hnd->bf_mem_block_size;
err = hnd->iface_hnd->bf_mem_block_wr(hnd, addr, regs, put_size);
if (!err) {
size -= put_size;
regs += put_size;
addr += put_size*4;
}
}
return err;
}
static int32_t f_bf_mem_rd(t_x502_hnd hnd, uint32_t addr, uint32_t* regs, uint32_t size) {
int err = 0;
while (!err && size) {
int get_size = (size < hnd->iface_hnd->bf_mem_block_size) ? size :
hnd->iface_hnd->bf_mem_block_size;
err = hnd->iface_hnd->bf_mem_block_rd(hnd, addr, regs, get_size);
if (!err) {
size -= get_size;
regs += get_size;
addr += get_size*4;
}
}
return err;
}
int32_t bf_fpga_reg_wr(t_x502_hnd hnd, uint32_t addr, uint32_t val) {
int32_t err = hnd->mode != X502_MODE_DSP ? X502_ERR_INVALID_MODE :
(hnd->bf_features & L502_BF_FEATURE_FPGA_REG_ACCESS) ?
X502_ERR_OK : X502_ERR_NOT_IMPLEMENTED;
if (err == X502_ERR_OK) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_FPGA_REG_WR, addr, &val, 1, NULL, 0,
X502_BF_CMD_DEFAULT_TOUT, NULL);
}
return err;
}
int32_t bf_fpga_reg_rd(t_x502_hnd hnd, uint32_t addr, uint32_t* val) {
int32_t err = hnd->mode != X502_MODE_DSP ? X502_ERR_INVALID_MODE :
(hnd->bf_features & L502_BF_FEATURE_FPGA_REG_ACCESS) ?
X502_ERR_OK : X502_ERR_NOT_IMPLEMENTED;
if (err == X502_ERR_OK) {
uint32_t recvd;
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_FPGA_REG_RD, addr, NULL, 0, val, 1,
X502_BF_CMD_DEFAULT_TOUT, &recvd);
if ((err == X502_ERR_OK) && (recvd < 1)) {
err = X502_ERR_BF_CMD_RETURN_INSUF_DATA;
}
}
return err;
}
static int32_t f_check_bf_firm(t_x502_hnd hnd) {
int32_t err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_BF_CMD, X502_BF_CMD_HDMA_RST);
if (!err) {
uint32_t rcv_wrds[2], recvd;
/* Проверяем версию прошивки BlackFin */
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_GET_PARAM, L502_BF_PARAM_FIRM_VERSION,
NULL, 0, rcv_wrds, 2, X502_BF_CMD_DEFAULT_TOUT, &recvd);
if (!err) {
if (recvd >= 1) {
hnd->bf_ver = rcv_wrds[0];
} else {
err = X502_ERR_BF_CMD_RETURN_INSUF_DATA;
}
hnd->bf_features = recvd >= 2 ? rcv_wrds[1] : 0;
}
}
/* Проверка состояния прошивки (запущен поток сбора или нет) */
if (!err) {
uint32_t mode, streams;
err = x502_bf_get_par(hnd, L502_BF_PARAM_STREAM_MODE, &mode, 1);
if (!err)
err = x502_bf_get_par(hnd, L502_BF_PARAM_ENABLED_STREAMS, &streams, 1);
if (!err) {
err = osspec_mutex_lock(hnd->mutex_cfg, BF_MUTEX_LOCK_TOUT);
if (!err) {
if (mode==L502_BF_MODE_IDLE) {
hnd->flags &= ~PRIV_FLAGS_STREAM_RUN;
} else {
hnd->flags |= PRIV_FLAGS_STREAM_RUN;
}
hnd->streams = streams;
osspec_mutex_release(hnd->mutex_cfg);
}
}
}
/* передаем информацию о модуле */
if (!err && !(hnd->flags & PRIV_FLAGS_STREAM_RUN)) {
uint32_t put_wrds[3];
uint32_t ch;
put_wrds[0] = hnd->info.devflags;
put_wrds[1] = hnd->info.fpga_ver | ((uint32_t)hnd->info.plda_ver<<16);
err = x502_bf_set_par(hnd, L502_BF_PARAM_MODULE_INFO, put_wrds, 2);
for (ch=0; !err && (ch < X502_DAC_CH_CNT); ch++) {
float* pk = (float*)&put_wrds[1];
float* po = (float*)&put_wrds[2];
put_wrds[0] = ch;
*pk = (float)hnd->info.cbr.dac[ch].k;
*po = (float)hnd->info.cbr.dac[ch].offs;
err = x502_bf_set_par(hnd, L502_BF_PARAM_DAC_COEF, put_wrds, 3);
}
}
if (!err && (hnd->mode!=X502_MODE_DSP))
err = X502_SetMode(hnd, X502_MODE_DSP);
return err;
}
X502_EXPORT(int32_t) X502_BfCheckFirmwareIsLoaded(t_x502_hnd hnd, uint32_t *version) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err) {
err = f_check_bf_firm(hnd);
if (!err && version)
*version = hnd->bf_ver;
}
return err;
}
X502_EXPORT(int32_t) X502_BfLoadFirmware(t_x502_hnd hnd, const char* filename) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (!err) {
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
err = hnd->iface_hnd->bf_firm_load(hnd, filename);
osspec_mutex_release(hnd->mutex_bf);
}
}
if (!err) {
SLEEP_MS(100);
err = f_check_bf_firm(hnd);
}
return err;
}
X502_EXPORT(int32_t) X502_BfMemWrite(t_x502_hnd hnd, uint32_t addr,
const uint32_t* regs, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;;
if (!err)
err = BF_CHECK_ADDR_SIZE(addr, size);
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
int32_t release_err;
err = f_bf_mem_wr(hnd, addr, regs, size);
release_err = osspec_mutex_release(hnd->mutex_bf);
if (!err)
err = release_err;
}
return err;
}
X502_EXPORT(int32_t) X502_BfMemRead(t_x502_hnd hnd, uint32_t addr,
uint32_t* regs, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (!err)
err = BF_CHECK_ADDR_SIZE(addr,size);
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
int32_t release_err;
err = f_bf_mem_rd(hnd, addr, regs, size);
release_err = osspec_mutex_release(hnd->mutex_bf);
if (!err)
err = release_err;
}
return err;
}
static int f_bf_start_cmd(t_x502_hnd hnd, uint16_t cmd_code, uint32_t par,
const uint32_t* data, uint32_t size) {
int err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (size > L502_BF_CMD_DATA_SIZE_MAX)
err = X502_ERR_BF_INVALID_CMD_DATA_SIZE;
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
t_l502_bf_cmd cmd;
cmd.code = cmd_code;
cmd.data_size = size;
cmd.param = par;
cmd.result = 0;
cmd.status = L502_BF_CMD_STATUS_REQ;
if (size!=0) {
memcpy(cmd.data, data, size*sizeof(data[0]));
}
/* если размер больше, чем можем записать за раз, то сперва записываем
* хвост, чтобы не получилось, что информация о команде будет записана
* раньше данных */
if (size > BF_CMD_FIRST_DATA_BLOCK_SIZE) {
err = f_bf_mem_wr(hnd, X502_BF_MEMADDR_CMD+X502_BF_REQ_DATA_SIZE_MAX*4,
&cmd.data[BF_CMD_FIRST_DATA_BLOCK_SIZE],
size - BF_CMD_FIRST_DATA_BLOCK_SIZE);
size = BF_CMD_FIRST_DATA_BLOCK_SIZE;
}
if (!err) {
err = f_bf_mem_wr(hnd, X502_BF_MEMADDR_CMD, (const uint32_t*)&cmd,
(offsetof(t_l502_bf_cmd, data))/4 + size);
}
if (err) {
osspec_mutex_release(hnd->mutex_bf);
}
}
return err;
}
static int f_bf_cmd_check(t_x502_hnd hnd, int32_t *res) {
t_l502_bf_cmd cmd;
int err = f_bf_mem_rd(hnd, X502_BF_MEMADDR_CMD, (uint32_t*)&cmd,
X502_BF_REQ_DATA_SIZE_MIN);
if (!err) {
if (cmd.status != L502_BF_CMD_STATUS_DONE) {
err = X502_ERR_BF_CMD_IN_PROGRESS;
} else if (res) {
*res = cmd.result;
}
}
if (err != X502_ERR_BF_CMD_IN_PROGRESS)
osspec_mutex_release(hnd->mutex_bf);
return err;
}
X502_EXPORT(int32_t) X502_BfExecCmd(t_x502_hnd hnd, uint16_t cmd_code, uint32_t par,
const uint32_t* snd_data, uint32_t snd_size,
uint32_t* rcv_data, uint32_t rcv_size, uint32_t tout,
uint32_t* recvd_size) {
t_l502_bf_cmd cmd;
int done = 0;
t_ltimer tmr;
int err;
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout));
err = f_bf_start_cmd(hnd, cmd_code, par, snd_data, snd_size);
while (!err && !done) {
err = f_bf_cmd_check(hnd, &cmd.result);
if (!err) {
done = 1;
if (rcv_size != 0) {
err = X502_BfMemRead(hnd, X502_BF_MEMADDR_CMD, (uint32_t*)&cmd,
(offsetof(t_l502_bf_cmd, data))/4 + rcv_size);
memcpy(rcv_data, cmd.data, rcv_size*sizeof(rcv_data[0]));
if (recvd_size!=NULL)
*recvd_size = cmd.data_size;
}
if (!err)
err = cmd.result;
} else if (err==X502_ERR_BF_CMD_IN_PROGRESS) {
if (ltimer_expired(&tmr)) {
err = X502_ERR_BF_CMD_TIMEOUT;
osspec_mutex_release(hnd->mutex_bf);
} else {
err = 0;
SLEEP_MS(20);
}
}
}
return err;
}