05-對(duì)part3-helloworld的搬運(yùn)和翻譯
非黑色字體為我自己添加,原文放在文章末尾
讓某些事情發(fā)生
????????目前位置我們的操作系統(tǒng)只有一個(gè)黑色的屏幕.我們?nèi)绾未_保我們的代碼確實(shí)運(yùn)行了呢?讓我們做一些更有趣的事情來(lái)展示出我們對(duì)硬件的控制.
????????通常,軟件開發(fā)人員所學(xué)的第一件事是在屏幕上打印出"hello world".然而在裸機(jī)開發(fā)中,在屏幕上打印可能是一個(gè)巨大的挑戰(zhàn),所以我么從簡(jiǎn)單的開始.
對(duì)串口(UART)的介紹
????????可能從我們的操作系統(tǒng)"發(fā)送信息"的最簡(jiǎn)單的方法就是通過(guò)串口或者串行通信電路.UART 是?Universal Asynchronous Receiver/Transmitter?(通用異步發(fā)射器/接收器)的縮寫,它非常古老而且簡(jiǎn)答,只用兩根線就能使兩個(gè)設(shè)備進(jìn)行通信.在USB到來(lái)之前,像鼠標(biāo),打印機(jī),調(diào)制調(diào)節(jié)器等設(shè)備均使用這種方式進(jìn)行連接.
????????我們將要直接把你的開發(fā)設(shè)備連接到你的樹莓派上,并且利用樹莓派發(fā)送"hello world"到你的開發(fā)設(shè)備上,你的開發(fā)設(shè)備將把它打印到屏幕上.
你將需要:
一個(gè)USB轉(zhuǎn)串口的線
下載并安裝驅(qū)動(dòng)(https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers)
在開發(fā)設(shè)備上下載并安裝PuTTY (https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html),實(shí)際上可以利用Pyserial這個(gè)庫(kù)編寫代碼來(lái)進(jìn)行串口控制
如果你使用Mac,我推薦安裝串口工具(https://apps.apple.com/gb/app/serialtools/id611021963?mt=12)作為PuTTY作為替代
????????如果你想要在我們開始前閱讀串口通信,我推薦SparkFun Website? ?(https://learn.sparkfun.com/tutorials/serial-communication/all)
????????關(guān)于串口的簡(jiǎn)單補(bǔ)充:
????????串口是一種十分簡(jiǎn)單的通信協(xié)議,在物理層面上只有兩根線,一根收,一根發(fā),而數(shù)據(jù)的組織上,串口由起始位,8bit/9bit數(shù)據(jù),校驗(yàn)位(看設(shè)置可選),停止位組成,串口是異步的,也就是說(shuō)連個(gè)設(shè)備用串口通信時(shí)不會(huì)傳輸時(shí)鐘以進(jìn)行信號(hào)同步(IIC或者SPI等就有時(shí)鐘,在這些通信設(shè)備里面誰(shuí)掌握時(shí)鐘誰(shuí)是主設(shè)備(master),剩下的是從設(shè)備(slaves)),因?yàn)闆](méi)有時(shí)鐘,所以雙方需要約定一個(gè)波特率,比如常見的9600(這個(gè)得自己先設(shè)置好),串口也沒(méi)有像TCP一樣的糾錯(cuò)機(jī)制,數(shù)據(jù)丟了就丟了,但是它就是簡(jiǎn)單好使,在低速,干擾不大的數(shù)據(jù)傳輸時(shí)很常見
把線連上
????????如果你安裝好了驅(qū)動(dòng),繼續(xù),把方形的USB接口連上你的電腦.幾乎沒(méi)有什么會(huì)發(fā)生,但是如果你現(xiàn)在打開控制面板,點(diǎn)擊設(shè)備管理器,并且打開"接口"這一節(jié),你會(huì)看見"Prolific"這個(gè)選項(xiàng),這就是說(shuō)我們的線正常工作了.
????????我的設(shè)備上是這樣的:

????????記下條目里面的 COMx 的數(shù)字,在我的機(jī)器上時(shí)COM5
????????同樣的線也能運(yùn)行在Mac上而無(wú)需額外驅(qū)動(dòng).
????????現(xiàn)在我們需要查看樹莓派來(lái)確認(rèn)線的另一端如何進(jìn)行連接.你需要尋找 GPIO 管腳(pin),它們一共有40個(gè),都在樹莓派版權(quán)聲明的上方.
????????下面這張圖顯示了你需要連接的地方.我推薦有突破引線的電線并且有如下的顏色編碼:
黑色=地
紅=+5V 電源
綠色=發(fā)送端(從USB發(fā)送到樹莓派)
白色=接收端(從USB接收樹莓派的發(fā)送)
????????接地的頭(我的例子里面時(shí)黑色線)接在樹莓派的地上(引腳6),發(fā)送的頭(白色)在TXD上(GPIO 14/引腳8)和接收的頭(綠色),在RXD上(GPIO 15/引腳 10).注意交叉連接RX和TX是必要的,比如把RX連到TX上,反之亦然(串口的線有RX和TX之分,樹莓派上的串口引腳也有RX和TX之分,而插串口的線的時(shí)候需要把RX的線連接到TX的引腳上,不然傳不了數(shù)據(jù)).當(dāng)我們使用專用電啟動(dòng)樹莓派時(shí),注意不要連接紅色的頭(多電源供電可能會(huì)燒掉芯片)

這是我正確連接了線的樹莓派:

設(shè)置PuTTY
在你的開發(fā)設(shè)備上運(yùn)行PuTTY
在左手邊的面板上點(diǎn)擊 "Session" 目錄
設(shè)置"Connection type"為 Serial
設(shè)置"Serial line to connect to"到我們之前找到的?COMx 的數(shù)字,我的時(shí)COM5
設(shè)置"Speed (baud)" 為?115200(baud為波特率,它和比特率略有區(qū)別,請(qǐng)自行百度相關(guān)概念)
確認(rèn)數(shù)據(jù)位為8bit,停止位為1,"Parity"為None,"Flow Contorl"為None
回到"Session"目錄你會(huì)發(fā)現(xiàn)設(shè)置已經(jīng)更改了
在"Saved Session"下面的文本框輸入名字,比如 "樹莓派4" 來(lái)保存設(shè)置,然后點(diǎn)擊保存(小心中文名稱導(dǎo)致找不到,建議使用英文名)
你可以通過(guò)雙擊"樹莓派4"來(lái)進(jìn)行連接,如果你這么做了,你因該可以看見一個(gè)空的黑窗口
????????如果你使用不同的終端模擬器,你需要遵循應(yīng)用程序供應(yīng)商關(guān)于如何使用軟件的執(zhí)導(dǎo)來(lái)設(shè)置成上面相同的設(shè)定.比如,Mac上的Serial Tools 在這里解釋.(https://www.w7ay.net/site/Applications/Serial%20Tools/)
快速改變 config.txt
????????你記得嗎,回到第一篇教程,我不得不編輯了SD上的 config.txt 文件,使我的樹莓派能成功在電視上顯示.現(xiàn)在我們需要加一條來(lái)確保UART是可靠的.
????????UART通信與時(shí)序關(guān)系較大,兩端在數(shù)據(jù)的收發(fā)速度上達(dá)成一致是很重要的.當(dāng)我們?cè)O(shè)置PuTTY的時(shí)候,我們告訴PuTTY以115200的波特率通信,我們需要樹莓派以相同的速率通信.事實(shí)上,我們不能確定它是否會(huì)-它可能以更快或者更慢的速率通信,取決于CPU多繁忙.
????????在config.txt里面加上這一行來(lái)解決這個(gè)問(wèn)題
core_freq_min=500
讓UART在代碼里運(yùn)行
????????首先,讓我們更新 kernel.c的代碼,來(lái)加一些新的調(diào)用.
#include "io.h"
void main()
{
? ? uart_init();
? ? uart_writeText("Hello world!\n");
? ? while (1);
}
????????我們從包括一個(gè)新的頭文件, io.h 來(lái)開始,這將允許我們?cè)?kernel.c文件外寫一些代碼,當(dāng)我們需要的時(shí)候可以調(diào)用它.
????????你要注意我們的main()函數(shù)也有一些新行,首先我們調(diào)用一個(gè)函數(shù)來(lái)實(shí)例化UART,然后我們調(diào)用另一個(gè)函數(shù)來(lái)寫入"Hello world".字符串末尾的奇怪字符 - \n - 是我們?cè)谖谋灸┪布尤胍粋€(gè)新行的方法,就像在文字處理程序里面輸入回車一樣!
????????現(xiàn)在我們用以下內(nèi)容創(chuàng)建 io.h
void uart_init();
void uart_writeText(char *buffer);
????????這是一個(gè)擁有兩個(gè)函數(shù)定義的,非常小的文件.(然而我覺(jué)得是函數(shù)聲明而不是函數(shù)定義).函數(shù)uart_init() 是一個(gè)返回值為 void 的函數(shù),并且沒(méi)有參數(shù),就像main() 一樣.這意味著它不需要來(lái)自調(diào)用者任何的數(shù)據(jù)來(lái)完成功能.而且它完成時(shí)不需要返回任何數(shù)據(jù)給調(diào)用者.你會(huì)注意到 uart_writeText 同樣是一個(gè)返回值為 void 的函數(shù),但是它需要一個(gè)參數(shù),因?yàn)槲覀円嬖V它寫什么.
????????我把實(shí)現(xiàn)這些的代碼放到另一個(gè)新文件中, io.c
// GPIO
enum {
? ? PERIPHERAL_BASE = 0xFE000000,
? ? GPFSEL0? ? ? ? ?= PERIPHERAL_BASE + 0x200000,
? ? GPSET0? ? ? ? ? = PERIPHERAL_BASE + 0x20001C,
? ? GPCLR0? ? ? ? ? = PERIPHERAL_BASE + 0x200028,
? ? GPPUPPDN0? ? ? ?= PERIPHERAL_BASE + 0x2000E4
};
enum {
? ? GPIO_MAX_PIN? ? ? ?= 53,
? ? GPIO_FUNCTION_ALT5 = 2,
};
enum {
? ? Pull_None = 0,
};
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
? ? unsigned int field_mask = (1 << field_size) - 1;
??
? ? if (pin_number > field_max) return 0;
? ? if (value > field_mask) return 0;?
? ? unsigned int num_fields = 32 / field_size;
? ? unsigned int reg = base + ((pin_number / num_fields) * 4);
? ? unsigned int shift = (pin_number % num_fields) * field_size;
? ? unsigned int curval = mmio_read(reg);
? ? curval &= ~(field_mask << shift);
? ? curval |= value << shift;
? ? mmio_write(reg, curval);
? ? return 1;
}
unsigned int gpio_set? ? ?(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
unsigned int gpio_clear? ?(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
unsigned int gpio_pull? ? (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
void gpio_useAsAlt5(unsigned int pin_number) {
? ? gpio_pull(pin_number, Pull_None);
? ? gpio_function(pin_number, GPIO_FUNCTION_ALT5);
}
// UART
enum {
? ? AUX_BASE? ? ? ? = PERIPHERAL_BASE + 0x215000,
? ? AUX_ENABLES? ? ?= AUX_BASE + 4,
? ? AUX_MU_IO_REG? ?= AUX_BASE + 64,
? ? AUX_MU_IER_REG? = AUX_BASE + 68,
? ? AUX_MU_IIR_REG? = AUX_BASE + 72,
? ? AUX_MU_LCR_REG? = AUX_BASE + 76,
? ? AUX_MU_MCR_REG? = AUX_BASE + 80,
? ? AUX_MU_LSR_REG? = AUX_BASE + 84,
? ? AUX_MU_CNTL_REG = AUX_BASE + 96,
? ? AUX_MU_BAUD_REG = AUX_BASE + 104,
? ? AUX_UART_CLOCK? = 500000000,
? ? UART_MAX_QUEUE? = 16 * 1024
};
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
void uart_init() {
? ? mmio_write(AUX_ENABLES, 1); //enable UART1
? ? mmio_write(AUX_MU_IER_REG, 0);
? ? mmio_write(AUX_MU_CNTL_REG, 0);
? ? mmio_write(AUX_MU_LCR_REG, 3); //8 bits
? ? mmio_write(AUX_MU_MCR_REG, 0);
? ? mmio_write(AUX_MU_IER_REG, 0);
? ? mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
? ? mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
? ? gpio_useAsAlt5(14);
? ? gpio_useAsAlt5(15);
? ? mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
}
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
void uart_writeByteBlockingActual(unsigned char ch) {
? ? while (!uart_isWriteByteReady());?
? ? mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
}
void uart_writeText(char *buffer) {
? ? while (*buffer) {
? ? ? ?if (*buffer == '\n') uart_writeByteBlockingActual('\r');
? ? ? ?uart_writeByteBlockingActual(*buffer++);
? ? }
}
????????你將會(huì)看到,在我們 io.h 文件中定義的兩個(gè)函數(shù)(個(gè)人依舊認(rèn)為 io.h 中是函數(shù)聲明而不是定義)?現(xiàn)在有了一些具體的代碼,并且有一些其他的支持的函數(shù).我將要在下一篇教程里解釋代碼是如何運(yùn)行的.但是讓我們現(xiàn)在掠過(guò),直接行動(dòng)起來(lái)吧.
????????有了你的 io.c 和 io.h 文件,并且改變了 kernel.c的代碼,運(yùn)行 make 來(lái)構(gòu)建你的新操作系統(tǒng).
然后:
復(fù)制你的新的 kernel8.img 到SD卡里,然后把SD卡放回樹莓派
確認(rèn)你的USB轉(zhuǎn)TTL線正確連接(記住電源線別連,不然別人成功你爆炸)
運(yùn)行你的終端模擬器,(比如PuTTY),并且連接到之前設(shè)置好的樹莓派上 - 你應(yīng)該看見一個(gè)空的黑窗口,并且沒(méi)有錯(cuò)誤.
啟動(dòng)你的樹莓派
????????如果您遵循了所有這些說(shuō)明,幾秒鐘后,您將在開發(fā)機(jī)器上的終端仿真器窗口中看到“Hello world!”
????????這是來(lái)自樹莓派的消息,表示操作系統(tǒng)正在工作。終于有證據(jù)了!
原文如下

Writing a "bare metal" operating system for Raspberry Pi 4 (Part 3)
Making something happen
So far our OS produces only a black screen. How can we be sure that our code is actually running? Let's do something a bit more interesting to really demonstrate that we have control of the hardware.
Usually, the first thing a software developer learns is to print "Hello world!" to the screen. In bare metal development however, printing to the screen can be quite a big challenge, so we're going to do something simpler to start with.
Introducing the UART
Perhaps the easiest way we can "send a message" from our OS is via the **UART** or serial communications circuit. UART stands for Universal Asynchronous Receiver/Transmitter and it's a very old and fairly simple interface that uses just two wires to communicate between two devices. Before USB came along, devices like mice, printers and modems were connected in this way.?
We're going to connect your dev machine directly to your RPi4 and have the RPi4 send the "Hello world!" message to your dev machine! Your dev machine will print it to the screen.
You will need:
?* A [USB to serial TTL cable](https://www.amazon.co.uk/gp/product/B01N4X3BJB/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)
?* To [download and install drivers for the cable](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)
?* To [download and install PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html) on your dev machine
?* If you're using a Mac, I'd recommend [installing Serial Tools](https://apps.apple.com/gb/app/serialtools/id611021963?mt=12) as an alternative to PuTTY
If you'd like to read up on serial communcation before we start, I recommend looking at the [SparkFun website](https://learn.sparkfun.com/tutorials/serial-communication/all).
Connecting the cable
If you have the drivers installed, go ahead and connect the cable to a spare USB port on your dev machine. Very little will happen, but if you now open Control Panel, click on Device Manager and open the Ports section, you should see a "Prolific" entry. That tells us that your cable is working correctly.
Here's what my machine looks like:

Make a note of the COMx number in brackets after the Prolific entry - in my case, that's **COM5**.
The same cable will work on a Mac without the need to install any drivers.
Now we need to look at the RPi4 to identify how to connect the other end of the cable. You'll be looking for the **GPIO pins**, all 40 of them, which are just above the Raspberry Pi copyright notice.?
The diagram below shows where you need to make connections. The cable I recommended has breakout leads that are colour-coded as follows:
?* BLACK = Ground
?* RED = +5v Power
?* GREEN = TX (transmits from USB port to RPi4)
?* WHITE = RX (receives to USB port from RPi4)
The Ground lead (BLACK in my case) hooks over the RPi4's Ground pin (Pin 6), the RX lead (WHITE) over TXD (GPIO 14/Pin 8) and the TX lead (GREEN) over RXD (GPIO 15/Pin 10). Note how it's necessary to cross RX and TX, i.e. connect RX to TX and vice versa. As we are powering the RPi4 using a dedicated power supply, make sure you **don't connect the RED connector**.

Here's my RPi4 with the cable connected correctly:

Setting up PuTTY
?* Run PuTTY on your dev machine
?* Click on the "Session" category in the left-hand pane
?* Set "Connection type" to Serial
?* Click on "Serial" under the "Connection" category in the left-hand pane
?* Set the "Serial line to connect to" to the COMx number we found above, mine was COM5
?* Set the "Speed (baud)" to 115200
?* Ensure "Data bits" is 8, "Stop bits" is 1, "Parity" is None and "Flow control" is None
?* Click back to the "Session" category in the left-hand pane and you should see the changed settings
?* Save these settings by typing a name e.g. "Raspberry Pi 4" in the textbox under "Saved Sessions" and clicking Save
?* You can now start the connection by double-clicking on "Raspberry Pi 4" - if you do, all you will see for now is an empty black window
If you're using a different terminal emulator, you'll need to use the same settings as above following the application vendor's instructions on how to use the software. For example, Serial Tools on Mac is explained [here](https://www.w7ay.net/site/Applications/Serial%20Tools/).
A quick config.txt change
Do you remember that, back in the first tutorial, I had to edit the _config.txt_ file on the SD card to get Raspbian up on my TV screen? Now we need to add a line to ensure that our UART connection will be reliable.
UART communication is a lot to do with timing, and it's important that both ends agree on the exact speed of data being sent/received. When we set up PuTTY, we told it to communicate at 115200 baud, and we'll need the RPi4 to communicate at the same rate. As it is, we can't be sure that it will - it might communicate faster or slower depending on how busy the CPU is.
Add this line to your _config.txt_ to resolve this:
```c
core_freq_min=500
```
Getting the UART going in code
First off, let's update _kernel.c_ to make a few new calls:
```c
#include "io.h"
void main()
{
? ? uart_init();
? ? uart_writeText("Hello world!\n");
? ? while (1);
}
```
We start by including a new **header file**, _io.h_. This allows us to write some new code outside of the _kernel.c_ file, and call it in when we need it.
You'll note that our `main()` routine has also some new lines. First we call a function to initialise the UART, and then we call another function to write "Hello world!" to it. The weird character at the end of the string - `\n` - is how we add a newline to the end of our text, just like pressing Enter in a word processor!
Let's now create _io.h_ with the following contents:
```c
void uart_init();
void uart_writeText(char *buffer);
```
This is a very short file with two **function definitions**. `uart_init()` is a **void function** with no **parameters**, just like `main()` is. This means that it doesn't need any data from the caller to do its job, and it doesn't send any data back to the caller when it's done. You'll note that `uart_writeText` is also a void function, but it does take a parameter since we need to tell it what text to write!
We'll put the actual code for these functions in another new file, _io.c_:
```c
// GPIO
enum {
? ? PERIPHERAL_BASE = 0xFE000000,
? ? GPFSEL0? ? ? ? ?= PERIPHERAL_BASE + 0x200000,
? ? GPSET0? ? ? ? ? = PERIPHERAL_BASE + 0x20001C,
? ? GPCLR0? ? ? ? ? = PERIPHERAL_BASE + 0x200028,
? ? GPPUPPDN0? ? ? ?= PERIPHERAL_BASE + 0x2000E4
};
enum {
? ? GPIO_MAX_PIN? ? ? ?= 53,
? ? GPIO_FUNCTION_ALT5 = 2,
};
enum {
? ? Pull_None = 0,
};
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
? ? unsigned int field_mask = (1 << field_size) - 1;
??
? ? if (pin_number > field_max) return 0;
? ? if (value > field_mask) return 0;?
? ? unsigned int num_fields = 32 / field_size;
? ? unsigned int reg = base + ((pin_number / num_fields) * 4);
? ? unsigned int shift = (pin_number % num_fields) * field_size;
? ? unsigned int curval = mmio_read(reg);
? ? curval &= ~(field_mask << shift);
? ? curval |= value << shift;
? ? mmio_write(reg, curval);
? ? return 1;
}
unsigned int gpio_set? ? ?(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
unsigned int gpio_clear? ?(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
unsigned int gpio_pull? ? (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
void gpio_useAsAlt5(unsigned int pin_number) {
? ? gpio_pull(pin_number, Pull_None);
? ? gpio_function(pin_number, GPIO_FUNCTION_ALT5);
}
// UART
enum {
? ? AUX_BASE? ? ? ? = PERIPHERAL_BASE + 0x215000,
? ? AUX_ENABLES? ? ?= AUX_BASE + 4,
? ? AUX_MU_IO_REG? ?= AUX_BASE + 64,
? ? AUX_MU_IER_REG? = AUX_BASE + 68,
? ? AUX_MU_IIR_REG? = AUX_BASE + 72,
? ? AUX_MU_LCR_REG? = AUX_BASE + 76,
? ? AUX_MU_MCR_REG? = AUX_BASE + 80,
? ? AUX_MU_LSR_REG? = AUX_BASE + 84,
? ? AUX_MU_CNTL_REG = AUX_BASE + 96,
? ? AUX_MU_BAUD_REG = AUX_BASE + 104,
? ? AUX_UART_CLOCK? = 500000000,
? ? UART_MAX_QUEUE? = 16 * 1024
};
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
void uart_init() {
? ? mmio_write(AUX_ENABLES, 1); //enable UART1
? ? mmio_write(AUX_MU_IER_REG, 0);
? ? mmio_write(AUX_MU_CNTL_REG, 0);
? ? mmio_write(AUX_MU_LCR_REG, 3); //8 bits
? ? mmio_write(AUX_MU_MCR_REG, 0);
? ? mmio_write(AUX_MU_IER_REG, 0);
? ? mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
? ? mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
? ? gpio_useAsAlt5(14);
? ? gpio_useAsAlt5(15);
? ? mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
}
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
void uart_writeByteBlockingActual(unsigned char ch) {
? ? while (!uart_isWriteByteReady());?
? ? mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
}
void uart_writeText(char *buffer) {
? ? while (*buffer) {
? ? ? ?if (*buffer == '\n') uart_writeByteBlockingActual('\r');
? ? ? ?uart_writeByteBlockingActual(*buffer++);
? ? }
}
```
You'll see that the two functions we defined in our _io.h_ header file now have some actual code, along with some other supporting functions. I'll explain what's going on in this code in the next tutorial, but let's skip straight to the action now!
With your new _io.c_ and _io.h_ files in place, as well as the changes to _kernel.c_ made, run `make` to build your new OS.?
Then:?
?* Copy the newly built _kernel8.img_ to the SD card, and then put the SD card into your RPi4
?* Make sure your USB to serial TTL cable is connected correctly
?* Run your terminal emulator (e.g. PuTTY) and connect to the "Raspberry Pi 4" session you set up earlier - you should see an empty black screen and no errors
?* Power on your RPi4
If you've followed all these instructions, after a few seconds you'll see "Hello world!" appear in the terminal emulator window on your dev machine.
It's a message from your RPi4 to say that your OS is working. Proof at last!