如何获取树莓派3的UART寄存器的值?

时间:2018-11-10 07:26:19

标签: raspberry-pi3 uart

我想问一些有关在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;
}

1 个答案:

答案 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()报告UARTIO和其他指针变量的值来确认这些语句(或调试代码)。


注意,大多数termios设置仅影响软件状态,而不影响UART寄存器,波特率,成帧和CRTSCTS(硬件流控制)是明显的例外情况