4个版本
0.2.2 | 2019年8月17日 |
---|---|
0.2.1 | 2019年8月15日 |
0.2.0 | 2019年7月20日 |
0.1.0 | 2019年7月16日 |
#16 in #launchpad
21KB
351 行
Monotron.
一个简单的1980年代家用电脑风格应用程序,用于Tiva-C Launchpad
Monotron不再存在
Monotron很有趣,但它只是一个技术演示,而不是我们可以构建的东西。查看https://github.com/neotron-compute/,了解我们新的基于ARM、由Rust驱动的家用电脑系列。
简介
Monotron由德州仪器TM4C123微控制器供电,包含一个ARM Cortex-M4核心和一些外围设备。选择这个处理器是因为它可以在廉价的开发套件Tiva-C Launchpad上使用,而且我恰好有一些。我给自己设定的挑战是,你能从这个微小的CPU中榨取多少?你能全部用纯Rust完成吗?
未来
Monotron已被Neotron 32取代,它是Neotron家族的一部分。所有未来的工作将在Neotron的旗帜下进行,这个仓库处于归档模式。
功能
- 800x600 8色VGA输出
- 32 KiB SRAM(24 KiB可用于应用程序)
- 256 KiB闪存ROM
- 可选低内存48x36文本显示模式或全384x288位图图形模式
- 8位单声道音频输出,带3通道、4波形合成器
- USB串行I/O
- Atari 9针游戏手柄接口
- 简单的命令行界面
- I2C扩展接口
- 可加载应用程序
- 带电池的实时时钟*
- 25针IBM PC风格并行打印机端口*
- MIDI输入、输出和透传*
- PS/2键盘和鼠标*
- RS-232串行端口*
- 请关注这个空间!
* 需要额外的硬件,包含在Monotron PCB中
视频
Monotron通过三个SPI外设和一个定时器生成800x600分辨率的60Hz VGA视频信号。它能这样做是因为VGA信号的像素时钟为40 MHz,而Tiva-C Launchpad的TM4C123 CPU运行在80 MHz。通过水平方向以半分辨率(400x600)运行,我们节省了需要通过SPI推送的像素数量,同时也将像素时钟减半到20 MHz。我尝试过40 MHz模式,但不起作用。
Monotron可以在VGA输出上显示两种“模式”。
文本模式
文本模式具有48字符 x 36行的显示。每个字符单元宽度为8像素,高度为16像素,可以显示8位MS-DOS代码页850字符集中的任何字符,并且可以有支持的任何前景和背景颜色。
- 白色
- 红色
- 黄色
- 绿色
- 青色
- 蓝色
- 品红色
- 黑色
文本缓冲区占用48 x 36 x 2 = 3,456
字节的SRAM。
内置字体来自FreeBSD。还有一个字体实现了电传文本块图形(或“sixels”)。
任何文本行都可以在“双倍高度”模式下显示,显示上半部分或下半部分。
最后,显示周围有一个8像素的边框和上下各12像素的边框,使一切整齐排列,并有助于解决使用实际CRT显示器时的任何轻微过度扫描问题。
图形模式
可以在运行时启用和禁用图形模式。默认情况下不启用,因为位图图形占用大量RAM!
您可以连接一个1位/像素的图形缓冲区,其长度为384像素的某个倍数(即384位或48字节)。此缓冲区通过行加倍(即每行显示两次)进行显示,因此您可以达到最大384x288分辨率,这将填满整个屏幕。位图的每个位都根据其所在的文本单元格(见上文)着色,类似于ZX Spectrum。全屏位图因此使用文本模式的3,456字节SRAM以及额外的384x288 / 8 = 13,824
字节SRAM。
编译
您需要使用Rust Nightly进行构建,因为我们需要用于嵌入式开发的某些实验性功能,这些功能在稳定版本中尚不可用。
$ rustup toolchain install nightly
$ git clone https://github.com/thejpster/monotron.git
$ cd monotron
$ rustup override set nightly
$ rustup target add thumbv7em-none-eabihf
$ cargo build --release
要编程板,可以使用lm4flash
$ cargo build --release
$ arm-none-eabi-objcopy -O binary ./target/thumbv7em-none-eabihf/release/monotron ./target/thumbv7em-none-eabihf/release/monotron.bin
$ lm4flash ./target/thumbv7em-none-eabihf/release/monotron.bin
或者您可以使用GDB进行调试(它将自动首先加载程序)
$ openocd
<switch to a different terminal>
$ cargo run --release
OpenOCD应读取我们的openocd.cfg
文件,该文件将其指向使用正确的配置。如果您没有权限打开USB设备,您可能需要运行sudo openocd
。
要退出GDB,您可能需要多次按Ctrl-C,因为它似乎有点卡住了。
连接
运行Monotron时,您有两个选项。
- 您可以使用裸Tiva-C Launchpad,并使用以下部分的引脚分配连接各种连接器。
- 或者,您可以跳过所有这些,自己制作Monotron PCB!
VGA
您的VGA连接器需要五根线
- 引脚1:红色 - 通过330欧姆电阻连接到PF1。
- 引脚2:绿色 - 通过330欧姆电阻连接到PB7。
- 引脚3:蓝色 - 通过330欧姆电阻连接到PD3。
- 引脚5:地 - 连接到GND
- 引脚6:红色返回 - 连接到GND
- 引脚7:绿色返回 - 连接到GND
- 引脚8:蓝色返回 - 连接到GND
- 引脚13:H-同步 - 连接到PB4
- 引脚14:V-同步 - 连接到PB5
我使用随机电阻,这是我在桌上找到的,这个配置对我有效(尽管画面有点暗,因为它实际上产生的是0.6V峰值,而不是0.7V)
-----+
| +------+ 330 Ohm Co-ax in the VGA cable
PB7 o+-----| |------------(o)==================)+
| +------+ |
-----+ |
+-+
| |
| | 75 Ohm
| | (in Monitor)
+-+
|
o
GND
330欧姆电阻与监视器中的75欧姆电阻形成电阻分压器。这是为了将3.3V输出降至0.7V。一些监视器比其他监视器更能容忍过电压。你使用的电阻越大,从GPIO引脚抽取的电流就越少(我们现在超过8mA,有点高),监视器看到的电压就越低,画面就越暗。相反,如果你降低电阻,电流就会更多,画面会更亮。为了保护你的芯片,请将亮度控制调高!
显然,上面只显示了其中一个通道 - 以完全相同的方式连接蓝色和红色通道。最后,别忘了保持你的线尽可能短!如果你尝试在10cm的无屏蔽线上发送20MHz信号,你会产生噪声。
在理想的世界里,你的板会提供一个75欧姆的源阻抗,匹配监视器的75欧姆阻抗,以减少反射,但在这个分辨率上这似乎并不重要。如果你想做到这一点,你需要制作一个电阻分压器将3.3V降至1.4V,然后通过一个高带宽(>20MHz)的单位增益放大器,在输出端使用一个75欧姆电阻。这对75欧姆电阻将把1.4V降至监视器中的0.7V。
UART
Monotron主要使用UART0,由Tiva-C Launchpad板上的板载伴侣芯片转换为USB串行。以115,200bps的速度连接到您最喜欢的串行终端,然后发送UTF-8字符,它们将被转换为虚拟键盘输入,让您可以驱动Monotron。
还有一个第二个UART(UART1),它有RTS/CTS硬件握手线连接(但没有DSR、DTR或RI)。在Monotron PCB上,这些连接到引脚头J8。通过在这个引脚头上安装六个跳线,可以激活板载MAX3232电平转换器,在DE9连接器J12上驱动RS-232信号。该连接器按数据终端设备或DTE(与数据通信设备或DCE相对)布线。这意味着Monotron在DE9引脚3上发送数据,并且它设计用于连接串行AT调制解调器或其他外围设备。其他计算机(如老式的IBM PC)甚至USB到RS-232适配器很可能布线为DTE,因此为了将其连接到Monotron,您很可能需要一个null-modem线(交换引脚3 + 4和引脚7 + 8)。
第一个编写Monotron BBS程序的人可以获得加分,该程序允许您使用56k调制解调器拨号。
第一个编写xmodem文件传输程序的人可以获得额外加分,这样您就可以从SD卡通过RS-232传输文件到旧MS-DOS 3.3 IBM PC上的xmodem实用程序。
注意:游戏手柄连接器看起来与RS232连接器相同 - 不要混淆它们!
在Monotron PCB上,第三个UART(UART3)通过多个光隔离器连接到MIDI In和MIDI Out端口。MIDI Through端口重复接收到的所有MIDI In端口上的内容。
最后,在Monotron PCB上,还有一个第四个UART(UART7),它连接到一个5V AtMega48,用作I/O扩展器。这个微控制器驱动两个PS/2端口(一个用于键盘,一个用于鼠标)以及一个全IBM PC风格的25针并行打印机端口。
Launchpad引脚 | Tiva-C引脚 | 外部引脚 | 功能(从Monotron的角度看) |
---|---|---|---|
不适用 | PA0 | 不适用 | USB串行Rx |
不适用 | PA1 | 不适用 | USB串行Tx |
J4.8 | PD6 | J12引脚3 | RS-232 Tx |
J4.9 | PD7 | J12引脚2 | RS-232 Rx |
J4.10 | PF4 | J12引脚7 | RS-232 RTS |
J3.2 | GND | J12引脚8 | RS-232 CTS |
J4.6 | PC6 | J11引脚4/5 | MIDI In |
J4.7 | PC7 | J9引脚4/5 | MIDI Out |
不适用 | 不适用 | J10引脚4/5 | MIDI Through |
音频
Monotron可以使用PE4引脚上的PWM生成8位音频输出。我使用了monotron-synth,它有一个三通道的wavetable合成器,可以使用方波、正弦波、锯齿波产生哔哔声和嘟嘟声,并生成白噪声。
您需要通过低通滤波器运行引脚以去除噪声,并将其连接到放大器,因为GPIO引脚实际上不会提供太多电流。
Launchpad引脚 | Tiva-C引脚 | TRS | 功能 |
---|---|---|---|
J1.5 | PE4 | 环/尖 | 音频左 |
J1.6 | PE5 | 尖 | 音频右 |
J3.2 | GND | 套筒 | 公共 |
目前音频仅从PE4(左)输出为单声道。如果这对您的放大器是问题,将PCB上的跳线J1设置为1-2可以将音频左也路由到套筒和尖。将J1设置为2-3可以启用立体声支持,如果将来开发的话。
游戏手柄
有五个低电平有效输入,分别对应向上、向下、向左、向右和开火。您可以将这些输入连接到标准的Atari或Commodore 9针游戏手柄,如下所示
Launchpad引脚 | Tiva-C引脚 | 游戏手柄引脚 | 功能 |
---|---|---|---|
J3.8 | PE2 | 1 | 向上 |
J3.9 | PE3 | 2 | 向下 |
J4.8 | PD6 | 3 | 向左 |
J4.9 | PD7 | 4 | 向右 |
J4.10 | PF4 | 6 | 开火 |
J3.2 | GND | 8 | 地 |
SeGA Master System (tm)控制器应该可以工作,但您只能使用按钮1,而不能使用按钮2。SeGA Mega Drive (tm)控制器可能无法工作,因为它有比引脚更多的按钮,因此使用5V供电的多路复用器在两个按钮组之间进行选择。15针模拟PC游戏手柄也无法工作。
SD卡
您可以从SD卡加载程序和数据,从第一个主MBR(标准旧式MS-DOS)分区,格式化为FAT16或FAT32。使用标准的SD卡SPI断开适配器,连接如下
Launchpad引脚 | Tiva-C引脚 | 功能 |
---|---|---|
J2.10 | PA2 | 时钟 |
J2.9 | PA3 | 芯片选择 |
J2.8 | PA4 | MISO/数据输出 |
J1.8 | PA5 | MOSI/数据输入 |
SD卡在3.3v下运行,因此不需要电平转换器,但许多卡需要在所有四个数据引脚上拉到3.3v(嗯,在10k和100k之间)。如果您不使用这些上拉,引脚将在Monotron启动时浮动,这些波动可能会扰乱SD卡,导致随机超时和其他异常效果。一些卡对此的容忍度更好,因此YMMV。如果有疑问,只需添加上拉(它们在PCB的版本0.7.0中缺失,但将在0.8.0+中出现)。
在控制台,您可以使用mount
命令扫描磁盘,然后使用dir
来显示根目录的内容。您还可以使用dload
、ddump
和dpage
命令来加载、十六进制转储并将文件打印到屏幕上。使用dload
加载的程序可以随后使用run
命令执行。
I2C
Monotron PCB板上的I2C扩展头连接到I2C1
。PCB板还可以选择性地安装一个Microchip MCP7940N电池后备实时时钟芯片。对此芯片的驱动支持TBC。
PCB板通过4.7k上拉电阻将I2C总线拉至5V。在这些特定的引脚上,TM4C123恰好是5V容差的,因此它只是以开漏模式运行I2C引脚,而不需要电平转换器。
Launchpad引脚 | Tiva-C引脚 | 外部引脚 | 功能 |
---|---|---|---|
J2.1 | GND | J6引脚1 | 地 |
J3.1 | 5V | J6引脚2 | 5V电源 |
J1.10 | PA7 | J6引脚3 | SDA |
J1.9 | PA6 | J6引脚4 | SCL |
PS/2键盘
初始的PS/2键盘支持有点工作,但不稳定,所以我再次将其移除。基本问题是,在没有使用SPI从设备(它们都在使用)的同时,在20 MHz的视频信号时序关键位上采样10到15 kHz的输入同步信号非常困难。要么你会丢失随机按键事件(导致丢失字符或卡键),要么每次按键时视频都会抖动(就像ZX81一样)。这两种情况都不理想。
在Monotron PCB上,我通过添加一个连接到UART 7的Atmel AtMega48微控制器作为I/O扩展器来解决这个问题。有关更多信息,请查看avr_kb
文件夹。
注意:0.7.0 PCB中存在一个错误,其中PS/2连接器的针脚排列与应有的相反。这是因为我虽然连接器图纸上清楚地写着“底部视图”,但我没有足够注意,假设它们是从上面看的!要使用PS/2连接器,它们必须安装在PCB的底部(即与所有其他连接器相反)。这个问题将在下一个PCB版本中修复。
MIDI
Monotron PCB板上有三个5针DIN MIDI端口:输入、输出和通过。这些端口连接到UART 3。
并行打印机端口
25针并行打印机端口连接到Monotron PCB板的AtMega48 I/O控制器。您向AtMega发送命令,让它驱动打印机端口。目前只计划支持SPP(经典单向支持,如原始IBM PC上所找到的)。对更复杂的EPP和ECP模式的支持TBD。
Monotron PCB
现在有一个PCB板了!它具有以下特点
- 2x20引脚接头,可与TM4C123 Launchpad配合使用(其他Launchpad,如TM4C129和MSP430尚未测试,几乎肯定不会工作)
- 5V电源插头(2.1mm圆柱形插头,中心为正极)
- VGA端口(DE15HD雌性)
- Atari/Commodore 游戏手柄端口(DE9雄性)
- Micro-SD卡插槽
- 3.5mm立体声音频输出
- RS-232端口(DE9雄性)
- 2.54mm(100mil)跳线,用于断开RS232驱动器,并允许您连接3.3v FTDI类型的TTL串行电缆。
- MIDI输入、输出和通过端口,带有光电隔离(5针DIN)
- 4针2.54mm间距(100mil)I2C扩展头(GND、5V、SDA、SCL)
- 带电池后备的Microchip MCP7940N I2C实时时钟
- AtMega48微控制器,控制
- IBM PC风格并行打印机端口(DB25雌性)
- PS/2键盘端口(6针迷你DIN)
- PS/2鼠标端口(6针迷你DIN)
请查看pcb文件夹中的Kicad文件、Gerbers和PDF原理图。如果您想购买PCB(带或不带元件套件),请通过Twitter向@therealjpster发送消息,或通过我的GitHub邮箱。Rev 0.7.0有一些粗糙的边缘,但我正在努力改进。
运行
运行时,会呈现一个简单的命令行驱动界面。命令可以通过串行或使用PS/2键盘输入。命令根据最左边的单词进行分割并解释。输入命令'help'以查看命令列表。一些命令会将您放入子菜单 - 使用'exit'返回到上一级菜单。
加载应用
可以将应用编译并加载到RAM中执行。它们必须链接到从地址0x2000_2000
运行,并且所有代码和数据总和小于24 KiB。请查看下表
地址 | 长度 | 描述 |
---|---|---|
0x0000_0000 | 256 KiB | OS代码 |
0x2000_0000 | 8 KiB | OS数据 |
0x2000_2000 | 24 KiB | 应用 |
图像的前四个字节必须是启动函数的地址,其原型为fn start(const struct callbacks_t* callbacks) -> int32
。除此之外,应用可以自由分配剩余的24,572字节。
注意: 应用不需要提供堆栈区域 - Monotron ROM将使用系统堆栈来处理。
提供给应用入口函数的回调结构定义在api.rs
中,但在C中看起来像
struct callbacks_t {
int32_t (*putchar)(void* p_context, char ch);
int32_t (*puts)(void* p_context, const char*);
int32_t (*readc)(void* p_context);
void (*wfvbi)(void* p_context);
int32_t (*kbhit)(void* p_context);
void (*move_cursor)(void* p_context, unsigned char row, unsigned char col);
int32_t (*play)(void* p_context, uint32_t frequency, uint8_t channel, uint8_t waveform, uint8_t volume);
void (*change_font)(void* p_context, uint32_t mode, const void* p_font);
uint8_t (*get_joystick)(void* p_context);
void (*set_cursor_visible)(void* p_context, uint8_t visible);
};
导出到应用的C函数是
puts
- 打印一个8位字符串(理解某些转义序列)。注意,与同名的C例程不同,此函数不会自动添加换行符。它更类似于fputs(s, stdout)
。putchar
- 打印一个8位字符readc
- 阻塞等待键盘/串行输入wfvbi
- 等待下一个垂直消隐间隔kbhit
- 如果按下了键(因此readc
不会阻塞),则返回1,否则返回0move_cursor
- 将光标移动到下一个打印的位置play
- 在合成器通道上播放一个音符change_font
- 改变屏幕上使用的字体,为正常CodePage 850、Teletext字体或应用提供的自定义字体get_joystick
- 返回摇杆输入的当前状态。位0-4分别对应开火、右、左、下和上。set_cursor_visible
- 将0传递以禁用_
光标,或将非零值传递以启用它。
您可以使用此存储库中的upload
Python脚本来将二进制图像上传到RAM,或使用dload
从SD卡加载它们。
请参阅monotron-apps,其中包含了将在Monotron RAM中运行的应用示例,以及一个包装器,使使用回调变得与使用常规C库一样简单。
未发布更改(将作为0.10.0版本发布)
- 通过在绘制像素之前进入WFI来修复视频中断抖动。
- 更新了VGA帧缓冲区回调API
变更日志
- 版本0.9.2 - 更新了菜单界面库
- 版本0.9.0 - 在Monotron PCB上添加了I2C命令和对AtMega键盘控制器(WIP)的支持。
- 版本0.8.0 - 向ABI添加了光标支持。添加了基本的SD卡支持(只读)。
- 版本0.7.0 - 将应用程序RAM移动到0x2000_2000。添加了光标支持。移动了回调指针。
- 版本0.6.3 - 修复了摇杆支持。
- 版本0.6.2 - 添加了摇杆支持。
- 版本0.6.1 - 添加了TeleText字体和在应用程序中切换字体的支持。
- 版本0.6.0 - 添加了声音和从RAM运行应用程序的支持。移除了PS/2键盘支持。
- 版本0.5.0 - 添加了1bpp图形模式。
- 版本0.4.0 - 添加了PS/2键盘支持。
- 版本0.3.0 - 退格键功能正常。
- 版本0.2.0 - 切换到文本缓冲区以节省RAM。基本动画功能正常。
- 版本0.1.0 - 首次发布。VGA输出工作正常,但菜单充满了虚拟命令,且没有键盘输入。
许可证
许可协议为以下之一
-
Apache License,版本2.0(《LICENSE-APACHE》或https://apache.ac.cn/licenses/LICENSE-2.0)
由您选择。
贡献
除非您明确声明,否则您提交给工作以包含在内的任何贡献,如Apache-2.0许可证中定义的,应按上述方式双重许可,不附加任何额外条款或条件。
lib.rs
:
Monotron API
该库包含Monotron的用户空间到内核API。
它由内核(github.com/thejpster/monotron)和各个用户空间示例应用程序(github.com/thejpster/monotron-apps)调用。
这里的API模仿了UNIX/POSIX API和MS-DOS API。我们使用函数指针而不是在结构中提供的SWI
(软件中断)调用。这个结构设计为可扩展。
可以使用cbindgen
生成此API的C头文件版本。
该文件中的所有类型都必须是#[repr(C)]
。