FPGA从串模式(slave serial)加载

1 篇文章 0 订阅

FPGA有多种不通的加载模式,模式由FPGA_M0、FPGA_M1、FPGA_M2三个引脚决定

通过原理图可以看到当前单板使用的模式是M[2:0]=111,即为从串模式

模式: slave serial (从串模式)

image.png

使用从串模式加载fpga用到的管脚如下:

Signal Name DirectionDescription
CCLKInputConfiguration clock.
PROGRAM_BInputActive-Low reset to configuration logic.
INIT_BInput/OutputActive-Low FPGA initialization pin. Indicates when the device is
ready to receive configuration data. Also indicates any
configuration errors. Can be held Low externally to delay
configuration.
DONEInput/OutputIndicates configuration is complete. Can be held Low externally
to delay start-up.
M[2:0]InputConfiguration mode selection.
D01_DINInputSerial configuration data input.
DOUTOutputData output for serial daisy chains.

具体对应到CPU的GPIO:

FPGA_PROG_B   GPIO0_C5

FPGA_INIT_B      GPIO0_B7

FPGA_DONE      GPIO0_C4

FPGA_CONFIG_DIN    GPIO0_C0

FPGA_CONFIG_CLK    GPIO0_C6

从手册中可以看到FPGA基本配置流程如下图:

image.png

手册中给到的伪代码如下:

/* Global defines
* Define the addresses for the I/O peripherals used to control and
* monitor the target FPGA. Also define the location in memory the
* bitstream is stored and its size. These are system dependent and
* should be adjusted as needed
*/
/* Output GPIO addresses */
CCLK_GPIO_BASEADDR = 0x40020000
PROGRAM_B_GPIO_BASEADDR = 0x40030000
SERIAL_OUT_GPIO_BASEADDR = 0x40040000
/* Input GPIO addresses */
INIT_B_GPIO_BASEADDR = 0x40050000
DONE_GPIO_BASEADDR = 0x40060000
/* Location in memory and size of the target bitstream */
MEMORY_BASEADDR = 0xC0000000
BITSTREAM_START_ADDR = MEMORY_BASEADDR + 0x2000000
BITSTREAM_SIZE_BYTES = 0xAEA68C
/* PROGRAM_B pulse width. Check the target FPGA data sheet for the
* TPROGRAM pulse width. One microsecond is safe for any 7 series FPGA
*/
TPROGRAM = 1 /* Assumes sleep() is microseconds */
/* Serialize a 32-bit word and clock each bit on the target's DIN and
* CCLK pins */
shift_word_out(data32)
{
  *cclk = CCLK_GPIO_BASEADDR
  *serial_out = SERIAL_OUT_GPIO_BASEADDR
  *cclk = 0
  *serial_out = 0
  for (i = 31; i >= 0; --i){
    *serial_out = (data32 & 1 << i) ? 1 : 0
    shift_cclk(1)
  }
}
/* Assert and Deassert CCLK */
shift_cclk(count)
{
  *cclk = CCLK_GPIO_BASEADDR
  *cclk = 0
  for (i = 0; i < count; --i) {
    *cclk = 1
    *cclk = 0
  }
}
int main()
{
  bits_start = BITSTREAM_START_ADDR
  bits_size = BITSTREAM_SIZE_BYTES
  *program_b = PROGRAM_B_GPIO_BASEADDR
  *init_b = INIT_B_GPIO_BASEADDR
  *done = DONE_GPIO_BASEADDR
  /* Configuration Reset */
  *program_b = 0
  sleep(TPROGRAM)
  *program_b = 1
  /* Wait for Device Initialization */
  while(*init_b == 0);
  
  /* Configuration (Bitstream) Load */
  for (i = 0; i < bits_size; i+=4) {
    shift_word_out(bits_start + i)
  }
  /* Check INIT_B */
  if (*init_b_pointer == 0) {
    return 1
  }
  /* Wait for DONE to assert */
  while(*done == 0)
  ;
  /* Compensate for Special Startup Conditions */
  shift_cclk(8)
  return 0
}

参考手册,使用gpio加载

#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/gpio.h>
#include <assert.h>
#include "fpga.h"
typedef unsigned int    uint32_t;
/* PROGRAM_B pulse width. Check the target FPGA data sheet for the
* TPROGRAM pulse width. One microsecond is safe for any 7 series FPGA
*/
#define TPROGRAM     1 /* Assumes sleep() is microseconds */
#define SWAP_BYTES   1
#define FPGABUFSIZE  4
#define FPGA_INIT_B    15
#define FPGA_PROG_B    21
#define FPGA_DONE      20
#define FPGA_CFG_CLK   22
#define FPGA_CFG_DIN   16
#define FPGA_PATH_NAME  "/userdata/fpga.bin"
int g_fdclk, g_fddin;
static const char values_str[] = "01";
/* Assert and Deassert CCLK */
void shift_cclk(uint32_t count)
{
    int i;
    for (i = 0; i < count; ++i) {
        write(g_fdclk, &values_str[1], 1);
        write(g_fdclk, &values_str[0], 1);
    }
}
/* Serialize a 32-bit word and clock each bit on the target's DIN and
* CCLK pins */
void shift_word_out(uint32_t data32)
{
    int i;
    for (i = 31; i >= 0; --i){
        write(g_fddin, &values_str[(data32 & 1 << i) ? 1 : 0], 1);
        shift_cclk(1);
    }
}
uint32_t swap_uint32(uint32_t data){
    uint32_t swapped;
    if (SWAP_BYTES == 1)
        swapped = ((data << 24) & 0xFF000000) |
            ((data << 8) & 0x00FF0000) |
            ((data >> 8) & 0x0000FF00) |
            ((data >> 24) & 0x000000FF);
    else 
        swapped = data;
    //printf("0x%08X: ", swapped );
    return swapped;
}
static void progress(unsigned long count, unsigned long total)
{
    unsigned long percent;
    
    percent = count * 100;
    if (total)
        percent = (unsigned) (percent / total);
    
    if((0 == count%100000) || (100 == percent))
    {
        printf("\r FpgaLoad: %lu/%lu (%u%%) ", count, total, (unsigned)percent);
    }
    
    fflush(NULL);
}
int bsp_fpga_bit_write(void)
{
    int fd_f;
    char *filename;
    struct stat statb;
    unsigned long done;
    unsigned long rem;
    unsigned long count;
    unsigned char buffer[FPGABUFSIZE] = {0};
    //static const char values_str[] = "01";
    char pathclk[64], pathdin[64];
    filename = FPGA_PATH_NAME;
    
    fd_f = open(filename, O_RDONLY);
    if (fd_f < 0)
    {
        printf("%s , file not found.\n", FPGA_PATH_NAME);
        return -1;
    }
    fstat(fd_f, &statb);
    printf("Fpga size is %d.\n", statb.st_size);
    
    snprintf(pathclk, sizeof(pathclk), "/sys/class/gpio/gpio%d/value", FPGA_CFG_CLK);
    snprintf(pathdin, sizeof(pathdin), "/sys/class/gpio/gpio%d/value", FPGA_CFG_DIN);
    g_fdclk = open(pathclk, O_WRONLY);
    if (g_fdclk < 0) {
        printf("Failed to open gpio FPGA_CFG_CLK for writing!\n");
        return -1;
    }
    g_fddin = open(pathdin, O_WRONLY);
    if (g_fddin < 0) {
        printf("Failed to open gpio FPGA_CFG_DIN for writing!\n");
        return -1;
    }
    done = 0;
    count = FPGABUFSIZE;
    if (write(g_fdclk, &values_str[0], 1) < 0) {
        printf("Failed to write value!\n");
        close(g_fdclk);
        return -1;
    }
    
    while(1)
    {
        rem = statb.st_size - done;
        if (rem == 0)
            break;
        if (rem < FPGABUFSIZE)
            count = rem;
        
        read(fd_f, buffer, count);
        
        if (count < FPGABUFSIZE)
            memset((char*)buffer + count, 0, FPGABUFSIZE - count);
        
        shift_word_out( swap_uint32( *(uint32_t *)(buffer) ));
        
        if (gpio_read(FPGA_INIT_B) == 0) {
            printf("INIT_B error\n");
            close(g_fdclk);
            close(g_fddin);
            return -1;
        }
        progress(done, statb.st_size);
        done += count;
    }
    printf("FPGA write finished.\n");
    close(g_fdclk);
    close(g_fddin);
    close(fd_f);
    return 0;
}
int bsp_fpga_serial_load(void)
{
    uint32_t i = 0;
    gpio_export(FPGA_INIT_B);
    gpio_export(FPGA_PROG_B);
    gpio_export(FPGA_DONE);
    gpio_export(FPGA_CFG_CLK);
    gpio_export(FPGA_CFG_DIN);
    gpio_direction(FPGA_PROG_B,1);
    gpio_direction(FPGA_CFG_CLK,1);
    gpio_direction(FPGA_CFG_DIN,1);
    /* Configuration Reset */
    gpio_write(FPGA_PROG_B, 0);
    sleep(TPROGRAM);
    gpio_write(FPGA_PROG_B, 1);
    /* Wait for Device Initialization */
    while(gpio_read(FPGA_INIT_B) == 0)
    {
        ++i;
        if (i > 0x00010000) {
            printf("waiting for INIT_B go high out of time.\n");
            return 1;
        }
    }
    printf("Downloading Bitstream to target FPGA.\n");
    /* Configuration (Bitstream) Load */
    if (bsp_fpga_bit_write() != 0)
    {
        printf("fpga bit write error.\n");
        return 1;
    }
    /* Check INIT_B */
    if (gpio_read(FPGA_INIT_B) == 0) {
        printf("INIT_B error\n");
        return 1;
    }
    /* Wait for DONE to assert */
    i = 0;
    while(gpio_read(FPGA_DONE) == 0)
    {
        shift_cclk(1);
        ++i;
        if (i > 0x00001000 ) {
            printf("DONE has not go high.\n");
            return 1;
        }
    }
    printf("FPGA Load successed!\n");
    /* Compensate for Special Startup Conditions */
    shift_cclk(8);
    return 0;
}

使用gpio方式加载需要代码中shift时钟,效率较低,实测整个加载流程耗时8min,严重超时

预留管脚足以支撑spi的单向传输,改为使用spi加载

spi加载fpga代码

int fpga_cfg_init(void)
{
    int fd, ret = 0;
    char *device = "/dev/spidev0.0";
    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");
    ret = ioctl(fd, SPI_IOC_WR_MODE32, &fmode);
    if (ret == -1)
        pabort("can't set spi mode");
    ret = ioctl(fd, SPI_IOC_RD_MODE32, &fmode);
    if (ret == -1)
        pabort("can't get spi mode");
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &fbits);
    if (ret == -1)
        pabort("can't set bits per word");
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &fbits);
    if (ret == -1)
        pabort("can't get bits per word");
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &fspeed);
    if (ret == -1)
        pabort("can't set max speed hz");
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &fspeed);
    if (ret == -1)
        pabort("can't get max speed hz");
    return fd;
}
static void progress(unsigned long count, unsigned long total)
{
    unsigned long percent;
    unsigned long printsize = 1024*1024;
    
    percent = count * 100;
    if (total)
        percent = (unsigned) (percent / total);
    if((0 == count%printsize) || (100 == percent)){
        printf("\r FpgaLoad: %lu/%lu (%u%%) ", count, total, (unsigned)percent);
    }
    
    fflush(NULL);
}
#define FPGA_BUFFER_SIZE    32*1024
void transfer_file(int fd, char *filename)
{
	ssize_t bytes;
	struct stat sb;
	int tx_fd;
	uint8_t *tx;
	uint8_t *rx;
	unsigned long done;
    unsigned long rem;
    unsigned long count;
	if (stat(filename, &sb) == -1)
		pabort("can't stat input file");
	tx_fd = open(filename, O_RDONLY);
	if (tx_fd < 0)
		pabort("can't open input file");
	tx = malloc(FPGA_BUFFER_SIZE);
	if (!tx)
		pabort("can't allocate tx buffer");
	rx = malloc(FPGA_BUFFER_SIZE);
	if (!rx)
		pabort("can't allocate rx buffer");
    done = 0;
    count = FPGA_BUFFER_SIZE;
    while(1)
    {
        rem = sb.st_size - done;
        if (rem == 0)
            break;
        if (rem < FPGA_BUFFER_SIZE)
            count = rem;
        bytes = read(tx_fd, tx, count);
            if (bytes != count)
                pabort("failed to read input file");
        
        if (count < FPGA_BUFFER_SIZE)
            memset((char*)tx + count, 0, FPGA_BUFFER_SIZE - count);
        
        transfers(fd, tx, rx, count);
        progress(done, sb.st_size);
        done += count;
    }
	free(rx);
	free(tx);
	close(tx_fd);
}

整个加载过程能在10s内完成,满足要求。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值