#applications #launchpad #ram #api #rom #running #monotron

monotron-api

定义了Monotron ROM与运行在RAM中的Monotron应用程序之间的API

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在YouTube上的视频截图 查看Monotron的实际操作!

未来

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时,您有两个选项。

  1. 您可以使用裸Tiva-C Launchpad,并使用以下部分的引脚分配连接各种连接器。
  2. 或者,您可以跳过所有这些,自己制作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来显示根目录的内容。您还可以使用dloadddumpdpage命令来加载、十六进制转储并将文件打印到屏幕上。使用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,否则返回0
  • move_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-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)]

没有运行时依赖