Intel Galileo 裸机 UART
Posted
技术标签:
【中文标题】Intel Galileo 裸机 UART【英文标题】:Intel Galileo bare metal UART 【发布时间】:2014-04-29 13:34:01 【问题描述】:我想在 Intel Galileo 板上编写一个小的“hello world”裸机应用程序。当然,使用 UEFI 打印文本(到 UART-1)效果很好,但我想“手动”访问 UART,而不需要 UEFI 的任何帮助。
在 QEMU 中我的代码运行良好:
.h 文件
#define COM1_PORT (0x03F8)
#define UART_PORT (COM1_PORT)
enum uart_port_offs_t
// DLAB RW
THR = 0, // 0 W Transmitter Holding Buffer
RBR = 0, // 0 R Receiver Buffer
DLL = 0, // 1 RW Divisor Latch Low Byte
IER = 1, // 0 RW Interrupt Enable Register
DLH = 1, // 1 RW Divisor Latch High Byte
IIR = 2, // - R Interrupt Identification Register
FCR = 2, // - RW FIFO Control Register
LCR = 3, // - RW Line Control Register
MCR = 4, // - RW Modem Control Register
LSR = 5, // - R Line Status Register
MSR = 6, // - R Modem Status Register
SR = 7, // - RW Scratch Register
;
.c 文件
void uart_init(void)
outb(UART_PORT + IER, 0x00); // Disable all interrupts
outb(UART_PORT + LCR, LCR_DLAB);
outb(UART_PORT + DLL, BAUD_LL); // Set divisor (lo byte)
outb(UART_PORT + DLH, BAUD_HL); // (hi byte)
outb(UART_PORT + LCR, LCR_WORD_BITS_8 | LCR_PAR_NONE | LCR_STOP_BITS_1);
outb(UART_PORT + FCR, FCR_ENABLE | FCR_CLR_RECV | FCR_CLR_SEND | FCR_TRIGGER_16);
outb(UART_PORT + MCR, MCR_DSR | MCR_RTS | MCR_AUX2);
ssize_t uart_write(const char *buf, size_t len)
size_t written = 0;
while (written < len)
while (!is_output_empty())
asm volatile ("pause");
outb(UART_PORT + THR, buf[written]);
++written;
return written;
主要
SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Exiting EFI boot services ...\r\n");
SystemTable->BootServices->ExitBootServices(ImageHandle, map_key);
uart_init();
while (1)
const char s[] = "UART\r\n";
uart_write(s, sizeof (s) - 1);
规格对我帮助不大。我猜英特尔 Galileo 板上的 UART 不使用/模拟普通/传统 COM 端口 3F8h、2F8h、3E8h 或 2E8h。
谁能告诉我我做错了什么,或者甚至发布一个最小的裸机 hello world 示例?
【问题讨论】:
可能是GPIO PWM和UART的复用?见原理图:communities.intel.com/docs/DOC-21822 1) 如果要禁用中断,为什么要设置MCR_AUX2
? 2)你的接收系统对于好的“QEMU”和坏的“UEFI”是一样的吗? IOW 你有什么证据证明事情不好? 3) 波特的值是多少?这可能取决于振荡器。
【参考方案1】:
我假设您的目标是串行端口,它是英特尔 Galileo 板上的“类音频”连接器。
以下是一些应该有所帮助的资源:
Galileo schematic Intel Quark SoC X1000 datasheet Intel Galileo IO Mapping Sergey 关于伽利略Configuring the Serial Port 的博客文章 Intel Quark Board Support Package downloads,包括 板级支持包源(目前ver.1.0.0) Intel Quark SoC X1000 UEFI Firmware Writer’s Guide有关此 UART 的注意事项:
这个串口作为 UART1 从 QUARK 芯片中出来(参见原理图)。 您可能需要操作一些 GPIO(请参阅 Sergey 的博客了解如何在 Linux 中执行此操作): gpio4:此 GPIO 控制 UART 信号和连接到 Quark SoC 的其他一些信号的电平转换器,例如 SPI 和快速 I/O。向此 GPIO 写入“1”可启用电平转换器。 gpio40:此 GPIO 控制引脚 0 的多路复用器。向此 GPIO 写入“0”会将引脚 0 连接到 UART 的 RxD(接收数据)信号。 gpio41:此 GPIO 控制引脚 1 的多路复用器。向此 GPIO 写入“0”会将引脚 1 连接到 UART 的 TxD(传输数据)信号。 查看 Quark 数据表中的第 18 章(高速 UART),了解在 UART 寄存器中放入的内容: 寄存器DLH、DLL指定波特率 决定是否需要 DMA 模式(第 18.3.1 章)、FIFO 中断模式(第 18.3.2 章)或 FIFO 轮询模式(第 18.3.3 章)。后者更简单但效率较低,恕我直言。前者还需要您正确配置 DMA。由于第 18 章有很多内容需要阅读(大约 67 页有用信息),我不会在这里重新输入所有内容,请阅读数据表并相应地配置寄存器。
一般说明:
对于裸机方法,首先确保您的引导过程正确,配置所有时钟选项、GPIO 默认模式和值、计时器(如果有)等。对于引导清单,请阅读 X1000 UEFI Firmware Writer’s Guide 中的第 4.12 章(启动这个芯片需要做大约 18 件事)。之后,我将使用 GPIO 上的简单“LED 闪烁”应用程序对其进行验证。
修补 3F8h 和类似端口不会有助于此 SoC 的“裸机”。您需要直接处理寄存器,或者找到并使用适当的库或框架(可能是 UEFI Bios?)。
特定平台的编程源代码应该是一个很好的例子。
例如,Board Support Package Sources for Intel Quark 中的存档 Quark_EDKII_v1.0.0.tar.gz
是 Quark/Galileo 的 UEFI 源代码。在那里,Serial.c 和 Serial.h 文件可能正是您要寻找的:
Quark_EDKII_v1.0.0/QuarkSocPkg/QuarkSouthCluster/Uart/Dxe/Serial.*
【讨论】:
以上是关于Intel Galileo 裸机 UART的主要内容,如果未能解决你的问题,请参考以下文章