我想问一些有关在raspberryPi3中获取miniUART寄存器值的问题。 我要做的是使串行发送器不带任何库。
首先,我使用“ termios”制作程序,并检查它是否正常运行 我想检查一下termios的库功能执行时哪些寄存器会更改。但是当我打印这些值时,它们始终为0。我找不到问题所在...
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define BUF_SIZE 1024
#define BLOCK_SIZE 1024
#define GPIO_BASE 0x7E210000
#define PERI_BASE 0x7E000000
#define UART_BASE (PERI_BASE + 0x00215000)
static volatile unsigned int *IO, *IER, *LCR, *MCR,
*LSR, *MSR, *SCRATCH, *CNTL, *STAT, *BAUD, *UART;
void init_reg(int fd);
void print_reg();
int main(int argc, char** argv){
int sfd = open("/dev/ttyS0", O_RDWR | O_NOCTTY );
if (sfd == -1){
printf( " eno : %d\n", errno);
printf("%s\n", strerror(errno));
return -1;
}
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if ( fd == -1){
printf("Fail to open /dev/mem\n");
return -1;
}
init_reg(fd);
struct termios options;
tcgetattr(sfd, &options);
cfsetspeed(&options, B9600);
print_reg();
cfmakeraw(&options);
options.c_cflag &= ~CSTOPB;
options.c_cflag |= CLOCAL;
options.c_cflag |= CREAD;
options.c_cc[VTIME] = 1;
options.c_cc[VMIN] = 100;
tcsetattr(sfd, TCSANOW, &options);
print_reg();
return 0;
}
void init_reg(int fd){
UART = (unsigned int*)mmap(0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, UART_BASE);
IO = UART + 0x40;
IER = UART + 0x44;
LCR = UART + 0x4C;
MCR = UART + 0x50;
LSR = UART + 0x54;
MSR = UART + 0x58;
SCRATCH = UART + 0x5C;
CNTL = UART + 0x60;
STAT = UART + 0x64;
BAUD = UART + 0x68;
}
void print_reg(){
print_binary("IO", (*IO));
print_binary("IER",(*IER));
print_binary("LCR",(*LCR));
print_binary("MCR",(*MCR));
print_binary("LSR",(*LSR));
print_binary("MSR",(*MSR));
print_binary("CNTL",(*CNTL));
print_binary("STAT",(*STAT));
print_binary("BAUD",(*BAUD));
print_binary("SCRATCH", (*SCRATCH));*/
return;
}
答案 0 :(得分:0)
我找不到问题所在。.
问题是您滥用了 mmap()返回的地址,您无法验证该地址。
返回的指针已分配给无符号整数类型的指针。
static volatile unsigned int ... *UART;
...
UART = (unsigned int*)mmap(...);
然后,您尝试使用(错误的)指针算法访问UART寄存器的内容,例如:
IO = UART + 0x40;
大概0x40(以及您使用的其他位移)是一个字节偏移量。
在<pointer> + <scaler>
的C表达式中,将<scaler>
表示为一个大小与指针类型相同的数量(例如sizeof(unsigned int)
)。
仅当指针是字节指针时,<scaler>
才表示字节数。
因此,由于UART
被声明为指向4字节字的指针,因此您在
IO = UART + 0x40;
等同于
IO = (unsigned int *)((unsigned char *)UART + (sizeof(unsigned int) * 0x40));
其中sizeof(unsigned int)
是4(字节),所应用的偏移量是您预期的四倍。
因此,您正在读取随机(可能不存在)的存储器位置,而不是访问UART硬件寄存器。当位置实际上无效时,这种编码错误会导致总线错误。
您可以使用 printf()报告UART
,IO
和其他指针变量的值来确认这些语句(或调试代码)。
注意,大多数termios设置仅影响软件状态,而不影响UART寄存器,波特率,成帧和CRTSCTS(硬件流控制)是明显的例外情况