FIRMWARE WORKING
This commit is contained in:
commit
a091567aa2
13 changed files with 1689 additions and 0 deletions
28
.cargo/config.toml
Normal file
28
.cargo/config.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# Choose a default "cargo run" tool:
|
||||
# - probe-run provides flashing and defmt via a hardware debugger, and stack unwind on panic
|
||||
# - elf2uf2-rs loads firmware over USB when the rp2040 is in boot mode
|
||||
# - "probe-rs-cli run" is similar to probe-run but it uses the latest probe-rs lib crate
|
||||
runner = "probe-run --chip RP2040"
|
||||
# runner = "elf2uf2-rs -d"
|
||||
# runner = "probe-rs-cli run --chip RP2040 --protocol swd"
|
||||
|
||||
rustflags = [
|
||||
"-C", "linker=flip-link",
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
|
||||
# Code-size optimizations.
|
||||
# trap unreachable can save a lot of space, but requires nightly compiler.
|
||||
# uncomment the next line if you wish to enable it
|
||||
# "-Z", "trap-unreachable=no",
|
||||
"-C", "inline-threshold=5",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
|
||||
[target.thumbv6m-none-eabi]
|
||||
runner = "elf2uf2-rs -d"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "debug"
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target/
|
1001
Cargo.lock
generated
Normal file
1001
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
82
Cargo.toml
Normal file
82
Cargo.toml
Normal file
|
@ -0,0 +1,82 @@
|
|||
[package]
|
||||
name = "rustgcc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.7.7"
|
||||
cortex-m-rt = "0.7.3"
|
||||
embedded-hal = { version = "0.2.7", features = ["unproven"] }
|
||||
|
||||
defmt = "0.3.2"
|
||||
defmt-rtt = "0.4.0"
|
||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
||||
|
||||
# We're using a Pico by default on this template
|
||||
rp-pico = "0.7.0"
|
||||
rp2040-hal = { version="0.8", features=["rt", "critical-section-impl"] }
|
||||
|
||||
pio-proc = "0.2"
|
||||
pio = "0.2"
|
||||
|
||||
# but you can use any BSP. Uncomment this to use the pro_micro_rp2040 BSP instead
|
||||
# sparkfun-pro-micro-rp2040 = "0.3"
|
||||
|
||||
# If you're not going to use a Board Support Package you'll need these:
|
||||
# rp2040-hal = { version="0.8", features=["rt", "critical-section-impl"] }
|
||||
# rp2040-boot2 = "0.2"
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true
|
||||
incremental = false
|
||||
opt-level = 3
|
||||
overflow-checks = true
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3
|
||||
overflow-checks = false
|
||||
strip = true
|
||||
|
||||
# do not optimize proc-macro crates = faster builds from scratch
|
||||
[profile.dev.build-override]
|
||||
codegen-units = 8
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
opt-level = 0
|
||||
overflow-checks = false
|
||||
|
||||
[profile.release.build-override]
|
||||
codegen-units = 8
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
opt-level = 0
|
||||
overflow-checks = false
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true
|
||||
incremental = false
|
||||
opt-level = 3
|
||||
overflow-checks = true
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3
|
39
Embed.toml
Normal file
39
Embed.toml
Normal file
|
@ -0,0 +1,39 @@
|
|||
[default.probe]
|
||||
protocol = "Swd"
|
||||
speed = 20000
|
||||
# If you only have one probe cargo embed will pick automatically
|
||||
# Otherwise: add your probe's VID/PID/serial to filter
|
||||
|
||||
## rust-dap
|
||||
# usb_vid = "6666"
|
||||
# usb_pid = "4444"
|
||||
# serial = "test"
|
||||
|
||||
|
||||
[default.flashing]
|
||||
enabled = true
|
||||
|
||||
[default.reset]
|
||||
enabled = true
|
||||
halt_afterwards = false
|
||||
|
||||
[default.general]
|
||||
chip = "RP2040"
|
||||
log_level = "WARN"
|
||||
# RP2040 does not support connect_under_reset
|
||||
connect_under_reset = false
|
||||
|
||||
[default.rtt]
|
||||
enabled = true
|
||||
up_mode = "NoBlockSkip"
|
||||
channels = [
|
||||
{ up = 0, down = 0, name = "name", up_mode = "NoBlockSkip", format = "Defmt" },
|
||||
]
|
||||
timeout = 3000
|
||||
show_timestamps = true
|
||||
log_enabled = false
|
||||
log_path = "./logs"
|
||||
|
||||
[default.gdb]
|
||||
enabled = false
|
||||
gdb_connection_string = "127.0.0.1:2345"
|
31
build.rs
Normal file
31
build.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
15
memory.x
Normal file
15
memory.x
Normal file
|
@ -0,0 +1,15 @@
|
|||
MEMORY {
|
||||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
}
|
||||
|
||||
EXTERN(BOOT2_FIRMWARE)
|
||||
|
||||
SECTIONS {
|
||||
/* ### Boot loader */
|
||||
.boot2 ORIGIN(BOOT2) :
|
||||
{
|
||||
KEEP(*(.boot2));
|
||||
} > BOOT2
|
||||
} INSERT BEFORE .text;
|
30
pio/joybus.pio
Normal file
30
pio/joybus.pio
Normal file
|
@ -0,0 +1,30 @@
|
|||
; THIS PIO PROGRAM EXPECTS THE SYSTEM CLOCK TO BE 125MHz
|
||||
|
||||
; Input is a succession of optional bools: (value/do we output something)
|
||||
; This makes so we can output an arbitrary number of bits without worrying about sizes
|
||||
; Useful since the end bit makes it so the output size is always = 1 [8]
|
||||
; Clock is / 5 i.e 25MHz
|
||||
; This will crash if fed an output of len == -1 [Z/8Z]
|
||||
.program joybus ;
|
||||
public inmode: ; Code must force a jump here once it's done using the out mode
|
||||
set pindirs, 0 ;
|
||||
inagain: ;
|
||||
wait 0 pin 0 [31] ; After the instruction complete we wait 61 cycles and read on the 62th
|
||||
nop [31] ;
|
||||
in pins, 1 ;
|
||||
wait 1 pin 0 ;
|
||||
jmp inagain ;
|
||||
;
|
||||
public outmode: ; External code must force a jump here in reaction to the RX FIFO contents
|
||||
set pins, 1 ;
|
||||
set pindirs, 1 ;
|
||||
outagain: ;
|
||||
pull ifempty block ; On pull 1 et ensuite on l'utilise pour X ET Y ?
|
||||
out x, 1 ; X = what should we output
|
||||
out y, 1 ; Y = should we output something
|
||||
jmp !y inmode ; if Y 0, empty the queue
|
||||
set pins, 0 [ 24 ] ;
|
||||
mov pins, x [ 24 ] ;
|
||||
mov pins, x [ 24 ] ;
|
||||
set pins, 1 [ 19 ] ;
|
||||
jmp outagain
|
74
src/gccstate.rs
Normal file
74
src/gccstate.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use core::ops::Deref;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GccState {
|
||||
pub a: bool,
|
||||
pub b: bool,
|
||||
pub x: bool,
|
||||
pub y: bool,
|
||||
pub start: bool,
|
||||
pub dup: bool,
|
||||
pub dleft: bool,
|
||||
pub dright: bool,
|
||||
pub ddown: bool,
|
||||
pub l: bool,
|
||||
pub r: bool,
|
||||
pub z: bool,
|
||||
pub lstickx: u8,
|
||||
pub lsticky: u8,
|
||||
pub rstickx: u8,
|
||||
pub rsticky: u8,
|
||||
}
|
||||
|
||||
impl GccState {
|
||||
pub fn new() -> GccState {
|
||||
GccState {
|
||||
a: false,
|
||||
b: false,
|
||||
x: false,
|
||||
y: false,
|
||||
start: false,
|
||||
dup: false,
|
||||
dleft: true,
|
||||
dright: false,
|
||||
ddown: false,
|
||||
l: false,
|
||||
r: false,
|
||||
z: true,
|
||||
lstickx: 127,
|
||||
lsticky: 127,
|
||||
rstickx: 127,
|
||||
rsticky: 127,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GccState> for [u8; 8] {
|
||||
fn from(value: GccState) -> Self {
|
||||
let mut response = [0; 8];
|
||||
|
||||
response[0] = (value.start as u8) << 4;
|
||||
response[0] |= (value.y as u8) << 3;
|
||||
response[0] |= (value.x as u8) << 2;
|
||||
response[0] |= (value.b as u8) << 1;
|
||||
response[0] |= (value.a as u8) << 0;
|
||||
|
||||
response[1] = 1 << 7;
|
||||
response[1] |= (value.l as u8) << 6;
|
||||
response[1] |= (value.r as u8) << 5;
|
||||
response[1] |= (value.z as u8) << 4;
|
||||
response[1] |= (value.dup as u8) << 3;
|
||||
response[1] |= (value.ddown as u8) << 2;
|
||||
response[1] |= (value.dright as u8) << 1;
|
||||
response[1] |= (value.dleft as u8) << 0;
|
||||
|
||||
response[2] = value.lstickx;
|
||||
response[3] = value.lsticky;
|
||||
response[4] = value.rstickx;
|
||||
response[5] = value.rsticky;
|
||||
response[6] = value.l as u8 * 127;
|
||||
response[7] = value.r as u8 * 127;
|
||||
|
||||
response
|
||||
}
|
||||
}
|
248
src/joybus.rs
Normal file
248
src/joybus.rs
Normal file
|
@ -0,0 +1,248 @@
|
|||
use cortex_m::{delay::Delay, singleton};
|
||||
use embedded_hal::digital::v2::{InputPin, OutputPin};
|
||||
use rp_pico::{
|
||||
hal::{
|
||||
dma::{double_buffer, single_buffer, DMAExt},
|
||||
gpio::{Pin, PinId, PinMode, Pins, ValidPinMode},
|
||||
pio::{
|
||||
InstalledProgram, Rx, StateMachine, StateMachineIndex, Stopped, Tx, UninitStateMachine,
|
||||
ValidStateMachine, PIO, SM0,
|
||||
},
|
||||
prelude::_rphal_pio_PIOExt,
|
||||
Sio,
|
||||
},
|
||||
pac::{self, Peripherals, PIO0, RESETS},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gccstate::GccState,
|
||||
pio::{to_pio_response, PioResponse},
|
||||
};
|
||||
|
||||
#[link_section = ".time_critical.init_state_machine"]
|
||||
fn init_state_machine<PE, SM>(
|
||||
pio: &mut PIO<PE>,
|
||||
sm: UninitStateMachine<(PE, SM)>,
|
||||
pin_id: u8,
|
||||
) -> (
|
||||
(StateMachine<(PE, SM), Stopped>, Rx<(PE, SM)>, Tx<(PE, SM)>),
|
||||
u8,
|
||||
i32,
|
||||
i32,
|
||||
)
|
||||
where
|
||||
PE: _rphal_pio_PIOExt,
|
||||
SM: StateMachineIndex,
|
||||
{
|
||||
let program_with_defines =
|
||||
pio_proc::pio_file!("./pio/joybus.pio", options(max_program_size = 32));
|
||||
let program = program_with_defines.program;
|
||||
|
||||
let installed = pio.install(&program).unwrap();
|
||||
|
||||
let offset = installed.offset();
|
||||
|
||||
(
|
||||
init_state_machine_with_installed_program(sm, pin_id, installed),
|
||||
offset,
|
||||
program_with_defines.public_defines.inmode,
|
||||
program_with_defines.public_defines.outmode,
|
||||
)
|
||||
}
|
||||
|
||||
#[link_section = ".time_critical.init_state_machine_with_installed_program"]
|
||||
fn init_state_machine_with_installed_program<PE, SM>(
|
||||
sm: UninitStateMachine<(PE, SM)>,
|
||||
pin_id: u8,
|
||||
installed: InstalledProgram<PE>,
|
||||
) -> (StateMachine<(PE, SM), Stopped>, Rx<(PE, SM)>, Tx<(PE, SM)>)
|
||||
where
|
||||
PE: _rphal_pio_PIOExt,
|
||||
SM: StateMachineIndex,
|
||||
{
|
||||
let (sm, rx, tx) = rp_pico::hal::pio::PIOBuilder::from_program(installed)
|
||||
.set_pins(pin_id, 1)
|
||||
.in_shift_direction(rp_pico::hal::pio::ShiftDirection::Left)
|
||||
.out_shift_direction(rp_pico::hal::pio::ShiftDirection::Right)
|
||||
.pull_threshold(32)
|
||||
.push_threshold(8)
|
||||
.clock_divisor_fixed_point(5, 0)
|
||||
.in_pin_base(pin_id)
|
||||
.autopush(true)
|
||||
.autopull(false)
|
||||
.out_pins(pin_id, 1)
|
||||
.build(sm);
|
||||
|
||||
(sm, rx, tx)
|
||||
}
|
||||
|
||||
#[link_section = ".time_critical.datatransfer"]
|
||||
pub fn datatransfer(
|
||||
pins: rp_pico::Pins,
|
||||
pio0: PIO0,
|
||||
mut resets: &mut RESETS,
|
||||
mut delay: Delay,
|
||||
) -> ! {
|
||||
let datapin = pins.gpio28.into_pull_up_input();
|
||||
|
||||
let datapin = datapin.into_mode::<rp2040_hal::gpio::pin::FunctionPio0>();
|
||||
|
||||
let (mut pio, sm0, _, _, _) = pio0.split(&mut resets);
|
||||
|
||||
delay.delay_us(100);
|
||||
|
||||
let ((mut sm, mut rx, mut tx), offset, offset_inmode, offset_outmode) =
|
||||
init_state_machine(&mut pio, sm0, datapin.id().num);
|
||||
|
||||
sm.exec_instruction(pio::Instruction {
|
||||
operands: pio::InstructionOperands::JMP {
|
||||
condition: pio::JmpCondition::Always,
|
||||
address: offset + offset_inmode as u8,
|
||||
},
|
||||
delay: 0,
|
||||
side_set: None,
|
||||
});
|
||||
|
||||
let mut s = sm.start();
|
||||
|
||||
let abutton = pins.gpio0.into_pull_up_input();
|
||||
|
||||
let mut ledpin = pins.led.into_push_pull_output();
|
||||
|
||||
loop {
|
||||
let data = loop {
|
||||
match rx.read() {
|
||||
Some(x) => break x as u8,
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if data == 0x40 {
|
||||
let mut state = GccState::new();
|
||||
|
||||
state.a = !abutton.is_high().unwrap();
|
||||
|
||||
match state.a {
|
||||
true => ledpin.set_high().unwrap(),
|
||||
false => ledpin.set_low().unwrap(),
|
||||
}
|
||||
|
||||
if state.a {
|
||||
state.lstickx = 255;
|
||||
}
|
||||
|
||||
let bitstate = state.into();
|
||||
|
||||
let pio_response: PioResponse<5> = to_pio_response(bitstate);
|
||||
|
||||
while rx.read().is_none() {}
|
||||
|
||||
let rumble = loop {
|
||||
match rx.read() {
|
||||
Some(x) => break x as u8,
|
||||
None => continue,
|
||||
}
|
||||
};
|
||||
|
||||
delay.delay_us(8);
|
||||
|
||||
// let (st, installed) = s.uninit(rx, tx);
|
||||
|
||||
// (sm, rx, tx) =
|
||||
// init_state_machine_with_installed_program(st, datapin.id().num, installed);
|
||||
|
||||
// sm.exec_instruction(pio::Instruction {
|
||||
// operands: pio::InstructionOperands::JMP {
|
||||
// condition: pio::JmpCondition::Always,
|
||||
// address: offset + offset_outmode as u8,
|
||||
// },
|
||||
// delay: 0,
|
||||
// side_set: None,
|
||||
// });
|
||||
|
||||
// s = sm.start();
|
||||
|
||||
let mut st = s.stop();
|
||||
st.exec_instruction(pio::Instruction {
|
||||
operands: pio::InstructionOperands::JMP {
|
||||
condition: pio::JmpCondition::Always,
|
||||
address: offset + offset_outmode as u8,
|
||||
},
|
||||
delay: 0,
|
||||
side_set: None,
|
||||
});
|
||||
s = st.start();
|
||||
|
||||
for i in 0..pio_response.len() {
|
||||
while !tx.write((*pio_response)[i]) {}
|
||||
}
|
||||
|
||||
// if rumble & 1 == 1 {
|
||||
// ledpin.set_high().unwrap();
|
||||
// } else {
|
||||
// ledpin.set_low().unwrap();
|
||||
// }
|
||||
} else if data == 0x41 {
|
||||
let origin_response: [u8; 10] = [0x00, 0x80, 127, 127, 127, 127, 0, 0, 0, 0];
|
||||
let pio_response: PioResponse<6> = to_pio_response(origin_response);
|
||||
|
||||
delay.delay_us(6);
|
||||
|
||||
let mut st = s.stop();
|
||||
st.exec_instruction(pio::Instruction {
|
||||
operands: pio::InstructionOperands::JMP {
|
||||
condition: pio::JmpCondition::Always,
|
||||
address: offset + offset_outmode as u8,
|
||||
},
|
||||
delay: 0,
|
||||
side_set: None,
|
||||
});
|
||||
s = st.start();
|
||||
|
||||
for i in 0..pio_response.len() {
|
||||
while !tx.write((*pio_response)[i]) {}
|
||||
}
|
||||
|
||||
// make ledpin blink twice with 500 ms delay
|
||||
} else if data == 0 {
|
||||
let probe_response: [u8; 3] = [0x09, 0x00, 0x03];
|
||||
let pio_response: PioResponse<2> = to_pio_response(probe_response);
|
||||
|
||||
delay.delay_us(6);
|
||||
|
||||
let mut st = s.stop();
|
||||
st.exec_instruction(pio::Instruction {
|
||||
operands: pio::InstructionOperands::JMP {
|
||||
condition: pio::JmpCondition::Always,
|
||||
address: offset + offset_outmode as u8,
|
||||
},
|
||||
delay: 0,
|
||||
side_set: None,
|
||||
});
|
||||
s = st.start();
|
||||
|
||||
for i in 0..pio_response.len() {
|
||||
while !tx.write((*pio_response)[i]) {}
|
||||
}
|
||||
} else {
|
||||
ledpin.set_high().unwrap();
|
||||
let (st, installed) = s.uninit(rx, tx);
|
||||
|
||||
(sm, rx, tx) =
|
||||
init_state_machine_with_installed_program(st, datapin.id().num, installed);
|
||||
|
||||
delay.delay_us(400);
|
||||
sm.exec_instruction(pio::Instruction {
|
||||
operands: pio::InstructionOperands::JMP {
|
||||
condition: pio::JmpCondition::Always,
|
||||
address: offset + offset_inmode as u8,
|
||||
},
|
||||
delay: 0,
|
||||
side_set: None,
|
||||
});
|
||||
s = sm.start();
|
||||
}
|
||||
}
|
||||
}
|
76
src/main.rs
Normal file
76
src/main.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
//! Blinks the LED on a Pico board
|
||||
//!
|
||||
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED.
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use bsp::entry;
|
||||
use defmt::*;
|
||||
use defmt_rtt as _;
|
||||
use embedded_hal::digital::v2::{InputPin, OutputPin};
|
||||
use panic_probe as _;
|
||||
|
||||
use rp2040_hal::xosc::CrystalOscillator;
|
||||
// Provide an alias for our BSP so we can switch targets quickly.
|
||||
// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change.
|
||||
use rp_pico as bsp;
|
||||
// use sparkfun_pro_micro_rp2040 as bsp;
|
||||
|
||||
use bsp::hal::{
|
||||
clocks::{init_clocks_and_plls, Clock},
|
||||
pac,
|
||||
sio::Sio,
|
||||
watchdog::Watchdog,
|
||||
};
|
||||
|
||||
use crate::joybus::datatransfer;
|
||||
|
||||
mod gccstate;
|
||||
mod joybus;
|
||||
mod pio;
|
||||
mod types;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
info!("Program start");
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let core = pac::CorePeripherals::take().unwrap();
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
let sio = Sio::new(pac.SIO);
|
||||
|
||||
// External high-speed crystal on the pico board is 12Mhz
|
||||
let external_xtal_freq_hz = 12_000_000u32;
|
||||
let clocks = init_clocks_and_plls(
|
||||
external_xtal_freq_hz,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
pac.PLL_USB,
|
||||
&mut pac.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
|
||||
|
||||
let pins = bsp::Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
|
||||
// This is the correct pin on the Raspberry Pico board. On other boards, even if they have an
|
||||
// on-board LED, it might need to be changed.
|
||||
// Notably, on the Pico W, the LED is not connected to any of the RP2040 GPIOs but to the cyw43 module instead. If you have
|
||||
// a Pico W and want to toggle a LED with a simple GPIO output pin, you can connect an external
|
||||
// LED to one of the GPIO pins, and reference that pin here.
|
||||
// let mut led_pin = pins.led.into_push_pull_output();
|
||||
|
||||
// let datapin = pins.gpio0.into_pull_up_input();
|
||||
|
||||
datatransfer(pins, pac.PIO0, &mut pac.RESETS, delay)
|
||||
}
|
||||
|
||||
// End of file
|
47
src/pio.rs
Normal file
47
src/pio.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PioResponse<const T: usize>([u32; T]);
|
||||
|
||||
impl<const T: usize> Deref for PioResponse<T> {
|
||||
type Target = [u32; T];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<const T: usize> DerefMut for PioResponse<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = ".time_critical.to_pio_response"]
|
||||
pub fn to_pio_response<const T: usize, const Y: usize>(value: [u8; T]) -> PioResponse<Y> {
|
||||
let mut response = PioResponse([0; Y]);
|
||||
|
||||
if T / 2 + 1 != Y {
|
||||
panic!("T / 2 + 1 != Y");
|
||||
}
|
||||
|
||||
if T == 0 {
|
||||
return response;
|
||||
}
|
||||
|
||||
for i in 0..(T / 2 + 1) {
|
||||
response[i] = 0;
|
||||
}
|
||||
|
||||
for i in 0..T {
|
||||
for j in 0..8 {
|
||||
response[i / 2] += 1 << (2 * (8 * (i % 2) + j) + 1);
|
||||
response[i / 2] +=
|
||||
(((value[i] & (0x80u8 >> j)) != 0) as u32) << (2 * (8 * (i % 2) + j));
|
||||
}
|
||||
}
|
||||
|
||||
response[T / 2] += 3 << (2 * (8 * (T % 2)));
|
||||
|
||||
response
|
||||
}
|
17
src/types.rs
Normal file
17
src/types.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
struct GccState {
|
||||
a: u8,
|
||||
b: u8,
|
||||
x: u8,
|
||||
y: u8,
|
||||
start: u8,
|
||||
dup: u8,
|
||||
dleft: u8,
|
||||
dright: u8,
|
||||
ddown: u8,
|
||||
l: u8,
|
||||
r: u8,
|
||||
lstickx: i8,
|
||||
lsticky: i8,
|
||||
rstickx: i8,
|
||||
rsticky: i8,
|
||||
}
|
Loading…
Reference in a new issue