当前位置:   article > 正文

FPGA从串模式(slave serial)加载_安路 eg4x fpga 从动串行加载模式

安路 eg4x fpga 从动串行加载模式

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

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

  1. /* Global defines
  2. * Define the addresses for the I/O peripherals used to control and
  3. * monitor the target FPGA. Also define the location in memory the
  4. * bitstream is stored and its size. These are system dependent and
  5. * should be adjusted as needed
  6. */
  7. /* Output GPIO addresses */
  8. CCLK_GPIO_BASEADDR = 0x40020000
  9. PROGRAM_B_GPIO_BASEADDR = 0x40030000
  10. SERIAL_OUT_GPIO_BASEADDR = 0x40040000
  11. /* Input GPIO addresses */
  12. INIT_B_GPIO_BASEADDR = 0x40050000
  13. DONE_GPIO_BASEADDR = 0x40060000
  14. /* Location in memory and size of the target bitstream */
  15. MEMORY_BASEADDR = 0xC0000000
  16. BITSTREAM_START_ADDR = MEMORY_BASEADDR + 0x2000000
  17. BITSTREAM_SIZE_BYTES = 0xAEA68C
  18. /* PROGRAM_B pulse width. Check the target FPGA data sheet for the
  19. * TPROGRAM pulse width. One microsecond is safe for any 7 series FPGA
  20. */
  21. TPROGRAM = 1 /* Assumes sleep() is microseconds */
  22. /* Serialize a 32-bit word and clock each bit on the target's DIN and
  23. * CCLK pins */
  24. shift_word_out(data32)
  25. {
  26. *cclk = CCLK_GPIO_BASEADDR
  27. *serial_out = SERIAL_OUT_GPIO_BASEADDR
  28. *cclk = 0
  29. *serial_out = 0
  30. for (i = 31; i >= 0; --i){
  31. *serial_out = (data32 & 1 << i) ? 1 : 0
  32. shift_cclk(1)
  33. }
  34. }
  35. /* Assert and Deassert CCLK */
  36. shift_cclk(count)
  37. {
  38. *cclk = CCLK_GPIO_BASEADDR
  39. *cclk = 0
  40. for (i = 0; i < count; --i) {
  41. *cclk = 1
  42. *cclk = 0
  43. }
  44. }
  45. int main()
  46. {
  47. bits_start = BITSTREAM_START_ADDR
  48. bits_size = BITSTREAM_SIZE_BYTES
  49. *program_b = PROGRAM_B_GPIO_BASEADDR
  50. *init_b = INIT_B_GPIO_BASEADDR
  51. *done = DONE_GPIO_BASEADDR
  52. /* Configuration Reset */
  53. *program_b = 0
  54. sleep(TPROGRAM)
  55. *program_b = 1
  56. /* Wait for Device Initialization */
  57. while(*init_b == 0);
  58. /* Configuration (Bitstream) Load */
  59. for (i = 0; i < bits_size; i+=4) {
  60. shift_word_out(bits_start + i)
  61. }
  62. /* Check INIT_B */
  63. if (*init_b_pointer == 0) {
  64. return 1
  65. }
  66. /* Wait for DONE to assert */
  67. while(*done == 0)
  68. ;
  69. /* Compensate for Special Startup Conditions */
  70. shift_cclk(8)
  71. return 0
  72. }

参考手册,使用gpio加载

  1. #define _GNU_SOURCE
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <getopt.h>
  9. #include <sys/ioctl.h>
  10. #include <string.h>
  11. #include <linux/gpio.h>
  12. #include <assert.h>
  13. #include "fpga.h"
  14. typedef unsigned int uint32_t;
  15. /* PROGRAM_B pulse width. Check the target FPGA data sheet for the
  16. * TPROGRAM pulse width. One microsecond is safe for any 7 series FPGA
  17. */
  18. #define TPROGRAM 1 /* Assumes sleep() is microseconds */
  19. #define SWAP_BYTES 1
  20. #define FPGABUFSIZE 4
  21. #define FPGA_INIT_B 15
  22. #define FPGA_PROG_B 21
  23. #define FPGA_DONE 20
  24. #define FPGA_CFG_CLK 22
  25. #define FPGA_CFG_DIN 16
  26. #define FPGA_PATH_NAME "/userdata/fpga.bin"
  27. int g_fdclk, g_fddin;
  28. static const char values_str[] = "01";
  29. /* Assert and Deassert CCLK */
  30. void shift_cclk(uint32_t count)
  31. {
  32. int i;
  33. for (i = 0; i < count; ++i) {
  34. write(g_fdclk, &values_str[1], 1);
  35. write(g_fdclk, &values_str[0], 1);
  36. }
  37. }
  38. /* Serialize a 32-bit word and clock each bit on the target's DIN and
  39. * CCLK pins */
  40. void shift_word_out(uint32_t data32)
  41. {
  42. int i;
  43. for (i = 31; i >= 0; --i){
  44. write(g_fddin, &values_str[(data32 & 1 << i) ? 1 : 0], 1);
  45. shift_cclk(1);
  46. }
  47. }
  48. uint32_t swap_uint32(uint32_t data){
  49. uint32_t swapped;
  50. if (SWAP_BYTES == 1)
  51. swapped = ((data << 24) & 0xFF000000) |
  52. ((data << 8) & 0x00FF0000) |
  53. ((data >> 8) & 0x0000FF00) |
  54. ((data >> 24) & 0x000000FF);
  55. else
  56. swapped = data;
  57. //printf("0x%08X: ", swapped );
  58. return swapped;
  59. }
  60. static void progress(unsigned long count, unsigned long total)
  61. {
  62. unsigned long percent;
  63. percent = count * 100;
  64. if (total)
  65. percent = (unsigned) (percent / total);
  66. if((0 == count%100000) || (100 == percent))
  67. {
  68. printf("\r FpgaLoad: %lu/%lu (%u%%) ", count, total, (unsigned)percent);
  69. }
  70. fflush(NULL);
  71. }
  72. int bsp_fpga_bit_write(void)
  73. {
  74. int fd_f;
  75. char *filename;
  76. struct stat statb;
  77. unsigned long done;
  78. unsigned long rem;
  79. unsigned long count;
  80. unsigned char buffer[FPGABUFSIZE] = {0};
  81. //static const char values_str[] = "01";
  82. char pathclk[64], pathdin[64];
  83. filename = FPGA_PATH_NAME;
  84. fd_f = open(filename, O_RDONLY);
  85. if (fd_f < 0)
  86. {
  87. printf("%s , file not found.\n", FPGA_PATH_NAME);
  88. return -1;
  89. }
  90. fstat(fd_f, &statb);
  91. printf("Fpga size is %d.\n", statb.st_size);
  92. snprintf(pathclk, sizeof(pathclk), "/sys/class/gpio/gpio%d/value", FPGA_CFG_CLK);
  93. snprintf(pathdin, sizeof(pathdin), "/sys/class/gpio/gpio%d/value", FPGA_CFG_DIN);
  94. g_fdclk = open(pathclk, O_WRONLY);
  95. if (g_fdclk < 0) {
  96. printf("Failed to open gpio FPGA_CFG_CLK for writing!\n");
  97. return -1;
  98. }
  99. g_fddin = open(pathdin, O_WRONLY);
  100. if (g_fddin < 0) {
  101. printf("Failed to open gpio FPGA_CFG_DIN for writing!\n");
  102. return -1;
  103. }
  104. done = 0;
  105. count = FPGABUFSIZE;
  106. if (write(g_fdclk, &values_str[0], 1) < 0) {
  107. printf("Failed to write value!\n");
  108. close(g_fdclk);
  109. return -1;
  110. }
  111. while(1)
  112. {
  113. rem = statb.st_size - done;
  114. if (rem == 0)
  115. break;
  116. if (rem < FPGABUFSIZE)
  117. count = rem;
  118. read(fd_f, buffer, count);
  119. if (count < FPGABUFSIZE)
  120. memset((char*)buffer + count, 0, FPGABUFSIZE - count);
  121. shift_word_out( swap_uint32( *(uint32_t *)(buffer) ));
  122. if (gpio_read(FPGA_INIT_B) == 0) {
  123. printf("INIT_B error\n");
  124. close(g_fdclk);
  125. close(g_fddin);
  126. return -1;
  127. }
  128. progress(done, statb.st_size);
  129. done += count;
  130. }
  131. printf("FPGA write finished.\n");
  132. close(g_fdclk);
  133. close(g_fddin);
  134. close(fd_f);
  135. return 0;
  136. }
  137. int bsp_fpga_serial_load(void)
  138. {
  139. uint32_t i = 0;
  140. gpio_export(FPGA_INIT_B);
  141. gpio_export(FPGA_PROG_B);
  142. gpio_export(FPGA_DONE);
  143. gpio_export(FPGA_CFG_CLK);
  144. gpio_export(FPGA_CFG_DIN);
  145. gpio_direction(FPGA_PROG_B,1);
  146. gpio_direction(FPGA_CFG_CLK,1);
  147. gpio_direction(FPGA_CFG_DIN,1);
  148. /* Configuration Reset */
  149. gpio_write(FPGA_PROG_B, 0);
  150. sleep(TPROGRAM);
  151. gpio_write(FPGA_PROG_B, 1);
  152. /* Wait for Device Initialization */
  153. while(gpio_read(FPGA_INIT_B) == 0)
  154. {
  155. ++i;
  156. if (i > 0x00010000) {
  157. printf("waiting for INIT_B go high out of time.\n");
  158. return 1;
  159. }
  160. }
  161. printf("Downloading Bitstream to target FPGA.\n");
  162. /* Configuration (Bitstream) Load */
  163. if (bsp_fpga_bit_write() != 0)
  164. {
  165. printf("fpga bit write error.\n");
  166. return 1;
  167. }
  168. /* Check INIT_B */
  169. if (gpio_read(FPGA_INIT_B) == 0) {
  170. printf("INIT_B error\n");
  171. return 1;
  172. }
  173. /* Wait for DONE to assert */
  174. i = 0;
  175. while(gpio_read(FPGA_DONE) == 0)
  176. {
  177. shift_cclk(1);
  178. ++i;
  179. if (i > 0x00001000 ) {
  180. printf("DONE has not go high.\n");
  181. return 1;
  182. }
  183. }
  184. printf("FPGA Load successed!\n");
  185. /* Compensate for Special Startup Conditions */
  186. shift_cclk(8);
  187. return 0;
  188. }

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

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

spi加载fpga代码

  1. int fpga_cfg_init(void)
  2. {
  3. int fd, ret = 0;
  4. char *device = "/dev/spidev0.0";
  5. fd = open(device, O_RDWR);
  6. if (fd < 0)
  7. pabort("can't open device");
  8. ret = ioctl(fd, SPI_IOC_WR_MODE32, &fmode);
  9. if (ret == -1)
  10. pabort("can't set spi mode");
  11. ret = ioctl(fd, SPI_IOC_RD_MODE32, &fmode);
  12. if (ret == -1)
  13. pabort("can't get spi mode");
  14. ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &fbits);
  15. if (ret == -1)
  16. pabort("can't set bits per word");
  17. ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &fbits);
  18. if (ret == -1)
  19. pabort("can't get bits per word");
  20. ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &fspeed);
  21. if (ret == -1)
  22. pabort("can't set max speed hz");
  23. ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &fspeed);
  24. if (ret == -1)
  25. pabort("can't get max speed hz");
  26. return fd;
  27. }
  28. static void progress(unsigned long count, unsigned long total)
  29. {
  30. unsigned long percent;
  31. unsigned long printsize = 1024*1024;
  32. percent = count * 100;
  33. if (total)
  34. percent = (unsigned) (percent / total);
  35. if((0 == count%printsize) || (100 == percent)){
  36. printf("\r FpgaLoad: %lu/%lu (%u%%) ", count, total, (unsigned)percent);
  37. }
  38. fflush(NULL);
  39. }
  40. #define FPGA_BUFFER_SIZE 32*1024
  41. void transfer_file(int fd, char *filename)
  42. {
  43. ssize_t bytes;
  44. struct stat sb;
  45. int tx_fd;
  46. uint8_t *tx;
  47. uint8_t *rx;
  48. unsigned long done;
  49. unsigned long rem;
  50. unsigned long count;
  51. if (stat(filename, &sb) == -1)
  52. pabort("can't stat input file");
  53. tx_fd = open(filename, O_RDONLY);
  54. if (tx_fd < 0)
  55. pabort("can't open input file");
  56. tx = malloc(FPGA_BUFFER_SIZE);
  57. if (!tx)
  58. pabort("can't allocate tx buffer");
  59. rx = malloc(FPGA_BUFFER_SIZE);
  60. if (!rx)
  61. pabort("can't allocate rx buffer");
  62. done = 0;
  63. count = FPGA_BUFFER_SIZE;
  64. while(1)
  65. {
  66. rem = sb.st_size - done;
  67. if (rem == 0)
  68. break;
  69. if (rem < FPGA_BUFFER_SIZE)
  70. count = rem;
  71. bytes = read(tx_fd, tx, count);
  72. if (bytes != count)
  73. pabort("failed to read input file");
  74. if (count < FPGA_BUFFER_SIZE)
  75. memset((char*)tx + count, 0, FPGA_BUFFER_SIZE - count);
  76. transfers(fd, tx, rx, count);
  77. progress(done, sb.st_size);
  78. done += count;
  79. }
  80. free(rx);
  81. free(tx);
  82. close(tx_fd);
  83. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/443548
推荐阅读
相关标签
  

闽ICP备14008679号