mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 11:31:31 +11:00
Add Serial and GPIO registers and implement embedded_hal traits (#96)
* Add Serial and GPIO registers and implement embedded_hal traits Use VolAddress and phantom_fields to populate the SIOCNT, RCNT, and SIODATA8 registers. Implement embedded_hal serial traits around an empty SioSerial struct. Hide serial read and write traits behind a "serial" feature flag to make embedded-hal and nb dependencies optional. * UART echo example Enable the serial feature for this example. Provide a pinout diagram to assist people with wiring up a USB to UART adapter.
This commit is contained in:
parent
b354dca479
commit
51c870281c
10
Cargo.toml
10
Cargo.toml
|
@ -11,13 +11,23 @@ license = "Apache-2.0"
|
||||||
|
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
serial = ["embedded-hal", "nb"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.10"
|
typenum = "1.10"
|
||||||
voladdress = "0.2"
|
voladdress = "0.2"
|
||||||
gba-proc-macro = "0.5"
|
gba-proc-macro = "0.5"
|
||||||
|
embedded-hal = { version = "0.2.4", optional = true }
|
||||||
|
nb = { version = "1.0.0", optional = true }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
incremental = false
|
incremental = false
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "uart_echo"
|
||||||
|
required-features = ["serial"]
|
||||||
|
|
31
examples/uart_echo.rs
Normal file
31
examples/uart_echo.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
// _ Link Cable Pinout
|
||||||
|
// ___/ \___ 1: VCC - 3.3V
|
||||||
|
// / \ 2: SO - TX
|
||||||
|
// | 1 3 5 | 3: SI - RX
|
||||||
|
// | 2 4 6 | 4: SD
|
||||||
|
// |_________| 5: SC
|
||||||
|
// 6: GND
|
||||||
|
|
||||||
|
use embedded_hal::prelude::*;
|
||||||
|
use gba::io::sio::{BaudRate, SioSerial};
|
||||||
|
use nb::block;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[start]
|
||||||
|
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
|
let mut serial = SioSerial;
|
||||||
|
SioSerial::init(BaudRate::Bps115200);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok(c) = block!(serial.read()) {
|
||||||
|
block!(serial.write(c)).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ pub mod display;
|
||||||
pub mod dma;
|
pub mod dma;
|
||||||
pub mod irq;
|
pub mod irq;
|
||||||
pub mod keypad;
|
pub mod keypad;
|
||||||
|
pub mod sio;
|
||||||
pub mod sound;
|
pub mod sound;
|
||||||
pub mod timers;
|
pub mod timers;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
183
src/io/sio.rs
Normal file
183
src/io/sio.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
//! Contains types and definitions for Serial IO registers.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Serial IO Control. Read/Write.
|
||||||
|
pub const SIOCNT: VolAddress<SioControlSetting> = unsafe { VolAddress::new(0x400_0128) };
|
||||||
|
|
||||||
|
/// Serial IO Data. Read/Write.
|
||||||
|
pub const SIODATA8: VolAddress<u16> = unsafe { VolAddress::new(0x400_012A) };
|
||||||
|
|
||||||
|
/// General IO Control. Read/Write.
|
||||||
|
pub const RCNT: VolAddress<IoControlSetting> = unsafe { VolAddress::new(0x400_0134) };
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
/// Setting for the serial IO control register.
|
||||||
|
///
|
||||||
|
/// * 0-1: `BaudRate`
|
||||||
|
/// * 2: Use hardware flow control
|
||||||
|
/// * 3: Use odd parity instead of even
|
||||||
|
/// * 4: TX buffer is full
|
||||||
|
/// * 5: RX buffer is empty
|
||||||
|
/// * 6: Error occurred
|
||||||
|
/// * 7: Use 8-bit data length instead of 7-bit
|
||||||
|
/// * 8: Use hardware FIFO
|
||||||
|
/// * 9: Enable parity check
|
||||||
|
/// * 10: Enable data receive
|
||||||
|
/// * 11: Enable data transmit
|
||||||
|
/// * 12-13: `SioMode`
|
||||||
|
/// * 14: Trigger interrupt on RX
|
||||||
|
SioControlSetting,
|
||||||
|
u16
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
impl SioControlSetting {
|
||||||
|
phantom_fields! {
|
||||||
|
self.0: u16,
|
||||||
|
baud_rate: 0-1=BaudRate<Bps9600,Bps38400,Bps57600,Bps115200>,
|
||||||
|
flow_control: 2,
|
||||||
|
parity_odd: 3,
|
||||||
|
tx_full: 4,
|
||||||
|
rx_empty: 5,
|
||||||
|
error: 6,
|
||||||
|
data_length_8bit: 7,
|
||||||
|
fifo_enable:8,
|
||||||
|
parity_enable: 9,
|
||||||
|
tx_enable: 10,
|
||||||
|
rx_enable: 11,
|
||||||
|
mode: 12-13=SioMode<Normal8Bit,MultiPlayer,Normal32Bit,Uart>,
|
||||||
|
irq_enable: 14,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newtype_enum! {
|
||||||
|
/// Supported baud rates.
|
||||||
|
BaudRate = u16,
|
||||||
|
/// * 9600 bps
|
||||||
|
Bps9600 = 0,
|
||||||
|
/// * 38400 bps
|
||||||
|
Bps38400 = 1,
|
||||||
|
/// * 57600 bps
|
||||||
|
Bps57600 = 2,
|
||||||
|
/// * 115200 bps
|
||||||
|
Bps115200 = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
newtype_enum! {
|
||||||
|
/// Serial IO modes.
|
||||||
|
SioMode = u16,
|
||||||
|
/// * Normal mode: 8-bit data
|
||||||
|
Normal8Bit = 0,
|
||||||
|
/// * Multiplayer mode: 16-bit data
|
||||||
|
MultiPlayer = 1,
|
||||||
|
/// * Normal mode: 32-bit data
|
||||||
|
Normal32Bit = 2,
|
||||||
|
/// * UART (RS232) mode: 7 or 8-bit data
|
||||||
|
Uart = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
/// Setting for the general IO control register.
|
||||||
|
///
|
||||||
|
/// * 0: SC state
|
||||||
|
/// * 1: SD state
|
||||||
|
/// * 2: SI state
|
||||||
|
/// * 3: SO state
|
||||||
|
/// * 4: Set SC as output, instead of input
|
||||||
|
/// * 5: Set SD as output, instead of input
|
||||||
|
/// * 6: Set SI as output, instead of input
|
||||||
|
/// * 7: Set SO as output, instead of input
|
||||||
|
/// * 8: Trigger interrupt on SI change
|
||||||
|
/// * 14-15: `IoMode`
|
||||||
|
IoControlSetting,
|
||||||
|
u16
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
impl IoControlSetting {
|
||||||
|
phantom_fields! {
|
||||||
|
self.0: u16,
|
||||||
|
sc: 0,
|
||||||
|
sd: 1,
|
||||||
|
si: 2,
|
||||||
|
so: 3,
|
||||||
|
sc_output_enable: 4,
|
||||||
|
sd_output_enable: 5,
|
||||||
|
si_output_enable: 6,
|
||||||
|
so_output_enable: 7,
|
||||||
|
si_irq_enable: 8,
|
||||||
|
mode: 14-15=IoMode<Disabled,GPIO,JoyBus>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newtype_enum! {
|
||||||
|
/// General IO modes.
|
||||||
|
IoMode = u16,
|
||||||
|
/// * IO disabled
|
||||||
|
Disabled = 0,
|
||||||
|
/// * General Purpose IO
|
||||||
|
GPIO = 2,
|
||||||
|
/// * JoyBus mode
|
||||||
|
JoyBus = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Empty stuct that implements embedded_hal traits.
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
pub struct SioSerial;
|
||||||
|
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
impl SioSerial {
|
||||||
|
/// Initialize SioSerial with provided baud rate and default 8N1 settings.
|
||||||
|
pub fn init(baud: BaudRate) {
|
||||||
|
RCNT.write(IoControlSetting::new());
|
||||||
|
SIOCNT.write(
|
||||||
|
// default settings: 8N1
|
||||||
|
SioControlSetting::new()
|
||||||
|
.with_baud_rate(baud)
|
||||||
|
.with_data_length_8bit(true)
|
||||||
|
.with_mode(SioMode::Uart)
|
||||||
|
.with_rx_enable(true)
|
||||||
|
.with_tx_enable(true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serial IO error type.
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
pub enum SioError {
|
||||||
|
/// * Error bit in SIOCNT is set
|
||||||
|
ErrorBitSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
impl embedded_hal::serial::Read<u8> for SioSerial {
|
||||||
|
type Error = SioError;
|
||||||
|
|
||||||
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
match SIOCNT.read() {
|
||||||
|
siocnt if siocnt.error() => Err(nb::Error::Other(SioError::ErrorBitSet)),
|
||||||
|
siocnt if siocnt.rx_empty() => Err(nb::Error::WouldBlock),
|
||||||
|
_ => Ok(SIODATA8.read() as u8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
impl embedded_hal::serial::Write<u8> for SioSerial {
|
||||||
|
type Error = SioError;
|
||||||
|
|
||||||
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
self.flush()?;
|
||||||
|
SIODATA8.write(word as u16);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
|
match SIOCNT.read() {
|
||||||
|
siocnt if siocnt.error() => Err(nb::Error::Other(SioError::ErrorBitSet)),
|
||||||
|
siocnt if siocnt.tx_full() => Err(nb::Error::WouldBlock),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue