PoC: boot, uart output in qemu
This commit is contained in:
commit
9b414e2408
|
@ -0,0 +1,11 @@
|
||||||
|
[target.armv7-unknown-linux-gnueabihf]
|
||||||
|
runner = "./runner.sh"
|
||||||
|
linker = "arm-none-eabihf-gcc"
|
||||||
|
rustflags = [
|
||||||
|
"-C", "link-arg=-Wl,-Tlink.x",
|
||||||
|
"-C", "target-feature=a9,armv7-a,neon",
|
||||||
|
"-C", "target-cpu=cortex-a9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "armv7-unknown-linux-gnueabihf"
|
|
@ -0,0 +1,46 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panic-abort"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r0"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcell"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile-register"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zc706"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
|
||||||
|
"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f"
|
||||||
|
"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
|
||||||
|
"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d"
|
||||||
|
"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
|
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "zc706"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
lto = false
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
lto = false
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
panic-abort = "0.3"
|
||||||
|
r0 = "0.2"
|
||||||
|
volatile-register = "0.2"
|
||||||
|
bit_field = "0.10"
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Put the linker script somewhere the linker can find it
|
||||||
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
File::create(out.join("link.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("link.x"))
|
||||||
|
.unwrap();
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
|
// Only re-run the build script when memory.x is changed,
|
||||||
|
// instead of when any part of the source code changes.
|
||||||
|
println!("cargo:rerun-if-changed=link.x");
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{ # Use master branch of the overlay by default
|
||||||
|
mozillaOverlay ? import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz),
|
||||||
|
rustSrc ? https://github.com/rustlang/rust/archive/master.tar.gz,
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; };
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
let
|
||||||
|
targets = [
|
||||||
|
"armv7-unknown-linux-gnueabihf"
|
||||||
|
];
|
||||||
|
rust =
|
||||||
|
rustChannelOfTargets "nightly" null targets;
|
||||||
|
rustPlatform = recurseIntoAttrs (makeRustPlatform {
|
||||||
|
rustc = rust // { src = rustSrc; };
|
||||||
|
cargo = rust;
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
inherit pkgs rustPlatform;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
ENTRY(_boot_cores);
|
||||||
|
|
||||||
|
/* SECTIONS */
|
||||||
|
/* { */
|
||||||
|
/* . = 0x8000; */
|
||||||
|
|
||||||
|
/* .text : */
|
||||||
|
/* { */
|
||||||
|
/* KEEP(*(.text.boot)) *(.text .text.*) */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Starts at LOADER_ADDR. */
|
||||||
|
. = 0x8000;
|
||||||
|
__start = .;
|
||||||
|
__text_start = .;
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
KEEP(*(.text.boot))
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096); /* align to page size */
|
||||||
|
__text_end = .;
|
||||||
|
|
||||||
|
__rodata_start = .;
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096); /* align to page size */
|
||||||
|
__rodata_end = .;
|
||||||
|
|
||||||
|
__data_start = .;
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096); /* align to page size */
|
||||||
|
__data_end = .;
|
||||||
|
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
bss = .;
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096); /* align to page size */
|
||||||
|
__bss_end = .;
|
||||||
|
__end = .;
|
||||||
|
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
/* Unused exception related info that only wastes space */
|
||||||
|
*(.ARM.exidx.*);
|
||||||
|
*(.ARM.extab.*);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
target remote :1234
|
||||||
|
|
||||||
|
# print demangled symbols by default
|
||||||
|
set print asm-demangle on
|
||||||
|
|
||||||
|
load
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e -m
|
||||||
|
|
||||||
|
ELF=$1
|
||||||
|
IMAGE=$ELF.bin
|
||||||
|
arm-none-eabihf-objcopy -O binary $ELF $IMAGE
|
||||||
|
qemu-system-arm -M xilinx-zynq-a9 -s -kernel $IMAGE -chardev file,id=uart0,path=/tmp/qemu.serial &
|
||||||
|
sleep 1
|
||||||
|
gdb -x qemu.gdb $ELF
|
||||||
|
kill -KILL %1
|
|
@ -0,0 +1,24 @@
|
||||||
|
let
|
||||||
|
mozillaOverlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
|
||||||
|
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; };
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
let
|
||||||
|
project = callPackage ./default.nix {};
|
||||||
|
in
|
||||||
|
with project;
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "adc2tcp-env";
|
||||||
|
buildInputs = with rustPlatform.rust; [
|
||||||
|
rustc cargo
|
||||||
|
pkgsCross.armhf-embedded.buildPackages.gcc
|
||||||
|
#pkgsCross.armv7l-hf-multiplatform.buildPackages.gcc
|
||||||
|
#pkgsCross.armhf-embedded.buildPackages.binutils
|
||||||
|
];
|
||||||
|
|
||||||
|
# Set Environment Variables
|
||||||
|
RUST_BACKTRACE = 1;
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/// The classic no-op
|
||||||
|
#[inline]
|
||||||
|
pub fn nop() {
|
||||||
|
unsafe { asm!("nop" :::: "volatile") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait For Event
|
||||||
|
#[inline]
|
||||||
|
pub fn wfe() {
|
||||||
|
unsafe { asm!("wfe" :::: "volatile") }
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod asm;
|
||||||
|
pub mod regs;
|
|
@ -0,0 +1,38 @@
|
||||||
|
pub trait ReadableRegister<T> {
|
||||||
|
fn get(&self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! def_reg_get {
|
||||||
|
($name:ty, $type:ty, $asm_instr:tt) => {
|
||||||
|
impl ReadableRegister<$type> for $name {
|
||||||
|
#[inline(always)]
|
||||||
|
fn get(&self) -> $type {
|
||||||
|
let mut value;
|
||||||
|
unsafe { asm!($asm_instr : "=r" (value) ::: "volatile") }
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WritableRegister<T> {
|
||||||
|
fn set(&self, value: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! def_reg_set {
|
||||||
|
($name:ty, $type:ty, $asm_instr:tt) => {
|
||||||
|
impl WritableRegister<$type> for $name {
|
||||||
|
#[inline(always)]
|
||||||
|
fn set(&self, value: $type) {
|
||||||
|
unsafe { asm!($asm_instr :: "r" (value) :: "volatile") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SP;
|
||||||
|
def_reg_get!(SP, u32, "mov $0, sp");
|
||||||
|
def_reg_set!(SP, u32, "mov sp, $0");
|
||||||
|
|
||||||
|
pub struct MPIDR;
|
||||||
|
def_reg_get!(MPIDR, u32, "mrc p15, 0, $0, c0, c0, 5");
|
|
@ -0,0 +1,50 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(asm)]
|
||||||
|
//[feature(global_asm)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
|
||||||
|
use panic_abort as _;
|
||||||
|
use r0::zero_bss;
|
||||||
|
|
||||||
|
mod cortex_a9;
|
||||||
|
mod slcr;
|
||||||
|
mod uart;
|
||||||
|
use uart::Uart;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static mut __bss_start: u32;
|
||||||
|
static mut __bss_end: u32;
|
||||||
|
static mut __end: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link_section = ".text.boot"]
|
||||||
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "C" fn _boot_cores() -> ! {
|
||||||
|
use cortex_a9::{asm, regs::*};
|
||||||
|
|
||||||
|
const CORE_MASK: u32 = 0x3;
|
||||||
|
// End of OCM RAM
|
||||||
|
const STACK_START: u32 = 256 << 10;
|
||||||
|
|
||||||
|
match MPIDR.get() & CORE_MASK {
|
||||||
|
0 => {
|
||||||
|
SP.set(STACK_START);
|
||||||
|
zero_bss(&mut __bss_start, &mut __bss_end);
|
||||||
|
main();
|
||||||
|
panic!("return from main");
|
||||||
|
}
|
||||||
|
_ => loop {
|
||||||
|
// if not core0, infinitely wait for events
|
||||||
|
asm::wfe();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let uart = Uart::uart0();
|
||||||
|
for b in "Hello World\r\n".bytes() {
|
||||||
|
uart.write_byte(b);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
use core::ops::RangeInclusive;
|
||||||
|
use volatile_register::{RO, WO, RW};
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct UartClkCtrl {
|
||||||
|
pub reg: RW<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UartClkCtrl {
|
||||||
|
const ADDR: *mut Self = 0xF8000154 as *mut _;
|
||||||
|
|
||||||
|
pub fn new() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::ADDR }
|
||||||
|
}
|
||||||
|
|
||||||
|
const DIVISOR: RangeInclusive<usize> = 8..=13;
|
||||||
|
const CLKACT1: usize = 1;
|
||||||
|
const CLKACT0: usize = 0;
|
||||||
|
|
||||||
|
pub fn enable_uart0(&self) {
|
||||||
|
unsafe {
|
||||||
|
self.reg.modify(|mut x| {
|
||||||
|
x.set_bits(Self::DIVISOR, 0x14);
|
||||||
|
x.set_bit(Self::CLKACT0, true);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct UartRstCtrl {
|
||||||
|
pub reg: RW<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UartRstCtrl {
|
||||||
|
const ADDR: *mut Self = 0xF8000228 as *mut _;
|
||||||
|
|
||||||
|
pub fn new() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::ADDR }
|
||||||
|
}
|
||||||
|
|
||||||
|
const UART1_REF_RST: usize = 3;
|
||||||
|
const UART0_REF_RST: usize = 2;
|
||||||
|
const UART1_CPU1X_RST: usize = 1;
|
||||||
|
const UART0_CPU1X_RST: usize = 0;
|
||||||
|
|
||||||
|
pub fn reset_uart0(&self) {
|
||||||
|
unsafe { toggle(&self.reg, Self::UART0_REF_RST); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_uart1(&self) {
|
||||||
|
unsafe { toggle(&self.reg, Self::UART1_REF_RST); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn toggle<T: BitField + Copy>(reg: &RW<T>, bit: usize) {
|
||||||
|
reg.modify(|x| {
|
||||||
|
let mut x = x.clone();
|
||||||
|
x.set_bit(bit, true);
|
||||||
|
x
|
||||||
|
});
|
||||||
|
reg.modify(|x| {
|
||||||
|
let mut x = x.clone();
|
||||||
|
x.set_bit(bit, false);
|
||||||
|
x
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
mod regs;
|
||||||
|
pub use regs::RegisterBlock;
|
||||||
|
|
||||||
|
pub struct Uart {
|
||||||
|
regs: &'static mut RegisterBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
pub fn uart0() -> Self {
|
||||||
|
let uart_rst_ctrl = super::slcr::UartRstCtrl::new();
|
||||||
|
uart_rst_ctrl.reset_uart0();
|
||||||
|
// TODO: Route UART 0 RxD/TxD Signals to MIO Pins
|
||||||
|
|
||||||
|
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
||||||
|
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
||||||
|
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1.
|
||||||
|
// d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0.
|
||||||
|
let uart_clk_ctrl = super::slcr::UartClkCtrl::new();
|
||||||
|
uart_clk_ctrl.enable_uart0();
|
||||||
|
|
||||||
|
Uart {
|
||||||
|
regs: RegisterBlock::uart0(),
|
||||||
|
}.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(self) -> Self {
|
||||||
|
self.regs.configure();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_byte(&self, v: u8) {
|
||||||
|
unsafe {
|
||||||
|
while self.regs.tx_fifo_full() {}
|
||||||
|
|
||||||
|
self.regs.write_byte(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
use volatile_register::{RO, WO, RW};
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
pub control: RW<u32>,
|
||||||
|
pub mode: RW<u32>,
|
||||||
|
pub intrpt_en: RW<u32>,
|
||||||
|
pub intrpt_dis: RW<u32>,
|
||||||
|
pub intrpt_mask: RO<u32>,
|
||||||
|
pub chnl_int_sts: WO<u32>,
|
||||||
|
pub baud_rate_gen: RW<u32>,
|
||||||
|
pub rcvr_timeout: RW<u32>,
|
||||||
|
pub rcvr_fifo_trigger_level: RW<u32>,
|
||||||
|
pub modem_ctrl: RW<u32>,
|
||||||
|
pub modem_sts: RW<u32>,
|
||||||
|
pub channel_sts: RO<u32>,
|
||||||
|
pub tx_rx_fifo: RW<u32>,
|
||||||
|
pub baud_rate_divider: RW<u32>,
|
||||||
|
pub flow_delay: RW<u32>,
|
||||||
|
pub reserved0: RO<u32>,
|
||||||
|
pub reserved1: RO<u32>,
|
||||||
|
pub tx_fifo_trigger_level: RW<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterBlock {
|
||||||
|
const UART0: *mut Self = 0xE0000000 as *mut _;
|
||||||
|
const UART1: *mut Self = 0xE0001000 as *mut _;
|
||||||
|
|
||||||
|
pub fn uart0() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::UART0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uart1() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::UART1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure(&self) {
|
||||||
|
unsafe {
|
||||||
|
// Confiugre UART character frame
|
||||||
|
// * Disable clock-divider
|
||||||
|
// * 8-bit
|
||||||
|
// * no parity
|
||||||
|
// * 1 stop bit
|
||||||
|
// * Normal channel mode
|
||||||
|
self.mode.write(0x20);
|
||||||
|
|
||||||
|
// Configure the Buad Rate
|
||||||
|
self.disable_rx();
|
||||||
|
self.disable_tx();
|
||||||
|
|
||||||
|
// 9,600 baud
|
||||||
|
self.baud_rate_gen.write(651);
|
||||||
|
self.baud_rate_divider.write(7);
|
||||||
|
|
||||||
|
self.reset_rx();
|
||||||
|
self.reset_tx();
|
||||||
|
self.enable_rx();
|
||||||
|
self.enable_tx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn write_byte(&self, value: u8) {
|
||||||
|
self.tx_rx_fifo.write(value.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONTROL_RXEN: usize = 2;
|
||||||
|
const CONTROL_RXDIS: usize = 3;
|
||||||
|
const CONTROL_TXEN: usize = 4;
|
||||||
|
const CONTROL_TXDIS: usize = 5;
|
||||||
|
const CONTROL_TXRST: usize = 1;
|
||||||
|
const CONTROL_RXRST: usize = 0;
|
||||||
|
|
||||||
|
unsafe fn disable_rx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_RXEN, false);
|
||||||
|
x.set_bit(Self::CONTROL_RXDIS, true);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn disable_tx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_TXEN, false);
|
||||||
|
x.set_bit(Self::CONTROL_TXDIS, true);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable_rx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_RXEN, true);
|
||||||
|
x.set_bit(Self::CONTROL_RXDIS, false);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable_tx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_TXEN, true);
|
||||||
|
x.set_bit(Self::CONTROL_TXDIS, false);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn reset_rx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_RXRST, true);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn reset_tx(&self) {
|
||||||
|
self.control.modify(|mut x| {
|
||||||
|
x.set_bit(Self::CONTROL_TXRST, true);
|
||||||
|
x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHANNEL_STS_TXFULL: usize = 4;
|
||||||
|
|
||||||
|
pub fn tx_fifo_full(&self) -> bool {
|
||||||
|
self.channel_sts.read().get_bit(Self::CHANNEL_STS_TXFULL)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue