在上一次学习的基础上,添加uart 模块IP,,同时测试上次的自定义IP的读数据功能
1.硬件设计
1.1.添加uart
在IP Catalog中搜索uart
选择下图的IP。
配置如下图:偶校验、8bit数据、1bit停止位、115200波特率。
连线与pio基本一致,这里需要将rx和tx供给外部连接。然后将irq与HPS组件的f2h_irq0相连。
最后生成新的qsys系统保存。
1.2.顶层代码修改
打开顶层代码,添加uart的接收发送接口。
soc_system例化部分
编译生sof文件再转换成rbf文件复制到sd卡中。
软件设计
首先根据DE-10开发板 FPGA SOC学习(三)熟悉SOC开发流程的2.3.1.生成新的硬件头文件hps_o.h
然后修改DE-10开发板 FPGA SOC学习(五)在HPS上自定义Avalon总线组件实验中的main函数代码
在这之前需要了解一下altera的uart核的寄存器配置
在《Embedded Peripherals IP User Guide》
手册中有介绍,直接取intel官网搜索下载即可。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
#include "socal/alt_gpio.h"
#include "hps_0.h"
#include <string.h>
#define HW_REGS_BASE ( ALT_STM_OFST )
#define HW_REGS_SPAN ( 0x04000000 )
#define HW_REGS_MASK ( HW_REGS_SPAN - 1 )
#define LED_CTRL_DATA 0x01 //定义led的相对地址,对应硬件自定义IP时,在地址为1时对LED进行读写。
//uart字符打印函数
void uart_putc(char c ,unsigned long *h2p_lw_uart_addr)
{
unsigned short uart_status; //状态寄存器值
do{
uart_status = *(h2p_lw_uart_addr + 2);//读取状态寄存器
}while(!(uart_status & 0x40)); //等待状态寄存器 bit6(trdy)为 1
*(h2p_lw_uart_addr + 1) = c; //发送一个字符
}
//uart字符串打印
void uart_printf(char *str ,unsigned long *h2p_lw_uart_addr)
{
while(*str != '\0')//检测当前指针指向的数是否为空字符
{
uart_putc(*str ,h2p_lw_uart_addr); //发送一个字符
str++; //字符串指针+1
}
}
//串口字符接收函数
int uart_getc(unsigned long *h2p_lw_uart_addr) {
unsigned short uart_status; //状态寄存器值
do {
uart_status = *(h2p_lw_uart_addr + 2); //读取状态寄存器
} while (!(uart_status & 0x80)); //等待状态寄存器 bit7(rrdy)为 1
return *(h2p_lw_uart_addr + 0);//读取一个字符并作为函数返回值返回
}
//串口字符串接收函数
int uart_scanf(char *p,unsigned long *h2p_lw_uart_addr) {
int cnt = 0; //接收个数计数器
while (1) {
*p = uart_getc(h2p_lw_uart_addr); //读取一个字符的数据
cnt++;
if (*p == '\n') //判断数据是否为换行
return cnt; //换行则停止计数,返回当前接收的字符个数
else
p++; //接收指针增 1
}
}
int main() {
void *virtual_base;
int fd;
int loop_count;
int led_direction;
int led_mask;
int led_temp;
int i;
unsigned long *h2p_lw_led_addr;
unsigned long *h2p_lw_uart_addr;
// map the address space for the LED registers into user space so we can interact with them.
// we'll actually map in the entire CSR span of the HPS since we want to access various registers within that span
//打开MPU
if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) {
printf( "ERROR: could not open \"/dev/mem\"...\n" );
return( 1 );
}
//将外设地址段映射到用户空间
virtual_base = mmap( NULL, HW_REGS_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, HW_REGS_BASE );
if( virtual_base == MAP_FAILED ) {
printf( "ERROR: mmap() failed...\n" );
close( fd );
return( 1 );
}
h2p_lw_led_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + MY_LED_0_BASE ) & ( unsigned long)( HW_REGS_MASK ) );//led地址
h2p_lw_uart_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + UART_0_BASE ) & ( unsigned long)( HW_REGS_MASK ) );//uart地址
// toggle the LEDs a bit
*(h2p_lw_uart_addr + 4) = (int) (UART_0_FREQ / UART_0_BAUD + 0.5);//设置波特率115200
loop_count = 0;
led_mask = 0x01;
led_direction = 0; // 0: left to right direction
char rx_buf[128] = { 0 }; //定义一个 128 字节的接收数组
memset(rx_buf, 0, 128); //清除数组中内容
char c[20];
while( loop_count < 60 ) {
// control led
*(h2p_lw_led_addr+LED_CTRL_DATA ) = led_mask; //对LED端口赋值
led_temp = *(h2p_lw_led_addr);//读取LED端口数据,因为我把读地址设置为了0,所有读数据的地址发生了改变
printf("led_mask:%d led_temp:%d\n",led_mask,led_temp);
// wait 100ms
sprintf(c,"%d",led_temp);//将int数据转换成字符数据
uart_printf(&c[0],h2p_lw_uart_addr);//打印读入的数据
usleep( 100*1000 );
// update led mask
if (led_direction == 0){
led_mask <<= 1;
if (led_mask == (0x01 << (7-1)))
led_direction = 1;
}else{
led_mask >>= 1;
if (led_mask == 0x01){
led_direction = 0;
loop_count++;
}
}
uart_scanf(&rx_buf[0],h2p_lw_uart_addr); //接收一行数据到 rx_buf 中
for (i = 0; rx_buf[i]!='\0'; i++)
{
printf("%c", rx_buf[i]);
}
printf("\n%s\n",rx_buf);
//printf("%s",rx_buf); //打印当前接收到的字符串内容
uart_printf(&rx_buf[0],h2p_lw_uart_addr);//通过串口调试助手,发送数据到FPGA
} // while
// clean up our memory mapping and exit
if( munmap( virtual_base, HW_REGS_SPAN ) != 0 ) {
printf( "ERROR: munmap() failed...\n" );
close( fd );
return( 1 );
}
close( fd );
return( 0 );
}
最后生成可执行文件复制到sd卡中。
结果验证部分在之前的实验中已经做过,不再赘述。