STM32f407 网络接收 fpga 的 bin 文件并更新到 fpga series7(3)
简介
实验 3:在搭建好 tcp 服务器,并拟定好协议的前提下,接收每一个 bin 文件的块,配置到 fpga。
原理图
fpga
fpga1
stm32
接线总结
// fpga引脚 stm32引脚
// 用不到D_OUT
#define PROGRAM_B PB0
#define INT_B PB1
#define CCLK PC10
#define D01_DIN PC12
#define DONE PD3
手册
搜索下载关键词:Xilinx XAPP583 Using a Microprocessor to Configure Xilinx 7 Series FPGAs
引脚
时序
伪代码在手册里,自己看
stm32cube 配置
单片机代码
load_fpga.c
#include "load_fpga.h"
#include <stdio.h>
#include "main.h"
#define WRITE_PROGRAM_B(x) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, x)
#define WRITE_CCLK(x) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, x)
#define WRITE_D01_DIN(x) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, x)
#define READ_INT_B() HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)
#define READ_DONE() HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_3)
/// @brief 交换4字节顺序
/// eg: 0xaabbccdd -> 0xddccbbaas
/// @param data
/// @return
unsigned int swap_uint32(unsigned int data) {
unsigned int swapped;
swapped = ((data << 24) & 0xFF000000) | ((data << 8) & 0x00FF0000) |
((data >> 8) & 0x0000FF00) | ((data >> 24) & 0x000000FF);
return swapped;
}
/// @brief 产生count个时钟上升沿
/// @param drvdata
/// @param count
void shift_cclk(unsigned int count) {
int i;
// WRITE_CCLK(0); // 感觉有点多余,影响接收速度了
for (i = 0; i < count; ++i) {
WRITE_CCLK(1);
WRITE_CCLK(0);
}
}
/// @brief 写入每一位,从高位开始
/// @param data32
void shift_word_out(unsigned int data32) {
int i;
unsigned int data;
for (i = 31; i >= 0; i--) {
data = (data32 & 1 << i) ? 1 : 0;
WRITE_D01_DIN(data);
shift_cclk(1);
}
}
/// @brief 准备写入
/// 配置准备下入状态
/// @param
/// @return 成功返回0
int program_init(void) {
int i = 0;
/* Configuration Reset */
WRITE_PROGRAM_B(0);
HAL_Delay(1); // 1us
WRITE_PROGRAM_B(1);
/* Wait for Device Initialization */
while (READ_INT_B() == 0) {
++i;
if (i > 0x00010000) {
printf("INIT_B has not gone high\n");
return -1;
}
}
return 0;
}
/// @brief 写入fpga
/// @param buf
/// @param len
/// @return 成功返回0
int program_data(char *buf, int len) {
int i;
for (i = 0; i < len; i += 4) {
shift_word_out(swap_uint32(*(uint32_t *)(buf + i)));
if (READ_INT_B() == 0) {
printf("INIT_B error\n");
return -1;
}
}
return 0;
}
/// @brief 写入完成
/// @param
/// @return 成功返回0
int program_done(void) {
/* Check INIT_B */
if (READ_INT_B() == 0) {
printf("INIT_B error\n");
return -1;
}
/* Wait for DONE to assert */
int i = 0;
while (READ_DONE() == 0) {
shift_cclk(1); // 不加会导致又概率失败
++i;
if (i > 0x00010000) {
printf("DONE has not gone high\n");
return -1;
}
}
/* Compensate for Special Startup Conditions */
shift_cclk(8);
return 0;
}
tcp_echo.c
#include "tcp_echo.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "load_fpga.h"
#if LWIP_NETCONN
#include "lwip/sys.h"
#include "lwip/api.h"
#define TCPECHO_THREAD_PRIO (tskIDLE_PRIORITY + 4)
#define kbuffer_len 1024
#define kheader_size 24
#define kdata_len 1000
#define kmagic 0xaa5555aa
char buffer[kbuffer_len];
struct tcp_package_header {
uint32_t magic;
uint32_t type;
uint32_t data_offset;
uint32_t data_len;
uint32_t order;
uint32_t magic1;
};
/// @brief TCP服务函数
/// @param arg
static void tcpecho_thread(void *arg) {
struct netconn *conn, *newconn;
err_t err, accept_err;
struct netbuf *buf;
void *data;
u16_t len;
int ret = 0;
LWIP_UNUSED_ARG(arg);
#if 1
/* Create a new connection identifier. */
conn = netconn_new(NETCONN_TCP);
if (conn != NULL) {
/* Bind connection to well known port number 7. */
err = netconn_bind(conn, NULL, 7);
if (err == ERR_OK) {
/* Tell connection to go into listening mode. */
netconn_listen(conn);
while (1) {
/* Grab new connection. */
accept_err = netconn_accept(conn, &newconn);
/* Process the new connection. */
if (accept_err == ERR_OK) {
while (netconn_recv(newconn, &buf) == ERR_OK) {
netbuf_data(buf, &data, &len);
do {
// 1 拿到帧头
struct tcp_package_header *head;
head = (struct tcp_package_header *)data;
// 2 判断type
switch (head->type) {
case 0xA: ret = program_init(); break;
case 0xB:
ret = program_data(
(char *)data + sizeof(struct tcp_package_header),
head->data_len);
break;
case 0xC: ret = program_done(); break;
default: break;
}
// 3 回发给tcp_client
if (ret < 0) {
head->data_offset = 1;
} else {
head->data_offset = 0;
}
netconn_write(newconn, head, sizeof(struct tcp_package_header),
NETCONN_COPY);
} while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
/* Close connection and discard connection identifier. */
netconn_close(newconn);
netconn_delete(newconn);
}
}
} else {
netconn_delete(newconn);
}
}
#endif
}
// 创建tcp服务函数任务
void tcpecho_init(void) {
sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE,
TCPECHO_THREAD_PRIO);
}
#endif /* LWIP_NETCONN */
加载前
加载后
上位机