781: embassy-net v2 r=Dirbaio a=Dirbaio - No more `dyn` - It's no longer a global singleton, you can create muliple net stacks at once. - You can't tear them down though, the Device it still has to be `'static` due to restrictions with smoltcp's "fake GAT" in the Device trait. :( - Removed `_embassy_rand` hack, random seed is passed on creation. 785: stm32: g0: add PLL clock source r=Dirbaio a=willglynn STM32G0 SYSCLK can be sourced from PLLRCLK. Given that the HSI runs at 16 MHz and the HSE range is 4-48 MHz, the PLL is the only way to reach 64 MHz. This commit adds `ClockSrc::PLL`. The PLL sources from either HSI16 or HSE, divides it by `m`, and locks its VCO to multiple `n`. It then divides the VCO by `r`, `p`, and `q` to produce up to three associated clock signals: * PLLRCLK is one of the inputs on the SYSCLK mux. This is the main reason the user will configure the PLL, so `r` is mandatory and the output is enabled unconditionally. * PLLPCLK is available as a clock source for the ADC and I2S peripherals, so `p` is optional and the output is conditional. * PLLQCLK exists only on STM32G0B0xx, and exists only to feed the MCO and MCO2 peripherals, so `q` is optional and the output is conditional. When the user specifies `ClockSrc::PLL(PllConfig)`, `rcc::init()` calls `PllConfig::init()` which initializes the PLL per [RM0454]. It disables the PLL, waits for it to stop, enables the source oscillator, configures the PLL, waits for it to lock, and then enables the appropriate outputs. `rcc::init()` then switches the clock source to PLLRCLK. `rcc::init()` is now also resonsible for calculating and setting flash wait states. SYSCLCK < 24 MHz is fine in the reset state, but 24-48 MHz requires waiting 1 cycle and 48-64 MHz requires waiting 2 cycles. (This was likely a blocker for anyone using HSE >= 24 MHz, with or without the PLL.) Flash accesses are now automatically slowed down as needed before changing the clock source, and sped up as permitted after changing the clock source. The number of flash wait states also determines if flash prefetching will be profitable, so that is now handled automatically too. [RM0454]: https://www.st.com/resource/en/reference_manual/rm0454-stm32g0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdf Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net> Co-authored-by: Will Glynn <will@willglynn.com>
This commit is contained in:
@ -8,7 +8,7 @@ resolver = "2"
|
||||
[dependencies]
|
||||
embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits"] }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
|
||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "medium-ethernet", "pool-16"] }
|
||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
||||
embedded-io = { version = "0.3.0", features = ["async"] }
|
||||
|
||||
defmt = "0.3"
|
||||
@ -28,11 +28,6 @@ micromath = "2.0.0"
|
||||
stm32-fmc = "0.2.4"
|
||||
embedded-storage = "0.3.0"
|
||||
|
||||
[dependencies.smoltcp]
|
||||
version = "0.8.0"
|
||||
default-features = false
|
||||
features = ["defmt"]
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
|
@ -2,90 +2,40 @@
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
use panic_probe as _;
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy::executor::{Executor, Spawner};
|
||||
use embassy::executor::Spawner;
|
||||
use embassy::time::{Duration, Timer};
|
||||
use embassy::util::Forever;
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_net::{Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator};
|
||||
use embassy_net::{Ipv4Address, Stack, StackResources};
|
||||
use embassy_stm32::eth::generic_smi::GenericSMI;
|
||||
use embassy_stm32::eth::{Ethernet, State};
|
||||
use embassy_stm32::interrupt;
|
||||
use embassy_stm32::peripherals::ETH;
|
||||
use embassy_stm32::peripherals::RNG;
|
||||
use embassy_stm32::rng::Rng;
|
||||
use embassy_stm32::time::U32Ext;
|
||||
use embassy_stm32::Config;
|
||||
use embassy_stm32::{interrupt, Peripherals};
|
||||
use embedded_io::asynch::Write;
|
||||
use heapless::Vec;
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
use panic_probe as _;
|
||||
use rand_core::RngCore;
|
||||
|
||||
macro_rules! forever {
|
||||
($val:expr) => {{
|
||||
type T = impl Sized;
|
||||
static FOREVER: Forever<T> = Forever::new();
|
||||
FOREVER.put_with(move || $val)
|
||||
}};
|
||||
}
|
||||
|
||||
type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>;
|
||||
|
||||
#[embassy::task]
|
||||
async fn main_task(
|
||||
device: &'static mut Ethernet<'static, ETH, GenericSMI, 4, 4>,
|
||||
config: &'static mut StaticConfigurator,
|
||||
spawner: Spawner,
|
||||
) {
|
||||
let net_resources = NET_RESOURCES.put(StackResources::new());
|
||||
|
||||
// Init network stack
|
||||
embassy_net::init(device, config, net_resources);
|
||||
|
||||
// Launch network task
|
||||
unwrap!(spawner.spawn(net_task()));
|
||||
|
||||
info!("Network task initialized");
|
||||
|
||||
// Then we can use it!
|
||||
let mut rx_buffer = [0; 1024];
|
||||
let mut tx_buffer = [0; 1024];
|
||||
let mut socket = TcpSocket::new(&mut rx_buffer, &mut tx_buffer);
|
||||
|
||||
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
|
||||
|
||||
let remote_endpoint = (Ipv4Address::new(192, 168, 0, 10), 8000);
|
||||
let r = socket.connect(remote_endpoint).await;
|
||||
if let Err(e) = r {
|
||||
info!("connect error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
info!("connected!");
|
||||
loop {
|
||||
let r = socket.write_all(b"Hello\n").await;
|
||||
if let Err(e) = r {
|
||||
info!("write error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
async fn net_task(stack: &'static Stack<Device>) -> ! {
|
||||
stack.run().await
|
||||
}
|
||||
|
||||
#[embassy::task]
|
||||
async fn net_task() {
|
||||
embassy_net::run().await
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn _embassy_rand(buf: &mut [u8]) {
|
||||
use rand_core::RngCore;
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
unwrap!(RNG_INST.as_mut()).fill_bytes(buf);
|
||||
});
|
||||
}
|
||||
|
||||
static mut RNG_INST: Option<Rng<RNG>> = None;
|
||||
|
||||
static EXECUTOR: Forever<Executor> = Forever::new();
|
||||
static STATE: Forever<State<'static, ETH, 4, 4>> = Forever::new();
|
||||
static ETH: Forever<Ethernet<'static, ETH, GenericSMI, 4, 4>> = Forever::new();
|
||||
static CONFIG: Forever<StaticConfigurator> = Forever::new();
|
||||
static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn config() -> Config {
|
||||
let mut config = Config::default();
|
||||
config.rcc.sys_ck = Some(400.mhz().into());
|
||||
@ -94,40 +44,83 @@ pub fn config() -> Config {
|
||||
config
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
#[embassy::main(config = "config()")]
|
||||
async fn main(spawner: Spawner, p: Peripherals) -> ! {
|
||||
info!("Hello World!");
|
||||
|
||||
info!("Setup RCC...");
|
||||
|
||||
let p = embassy_stm32::init(config());
|
||||
|
||||
let rng = Rng::new(p.RNG);
|
||||
unsafe {
|
||||
RNG_INST.replace(rng);
|
||||
}
|
||||
// Generate random seed.
|
||||
let mut rng = Rng::new(p.RNG);
|
||||
let mut seed = [0; 8];
|
||||
rng.fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
||||
let eth_int = interrupt::take!(ETH);
|
||||
let mac_addr = [0x10; 6];
|
||||
let state = STATE.put(State::new());
|
||||
let eth = unsafe {
|
||||
ETH.put(Ethernet::new(
|
||||
state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PG13, p.PB13,
|
||||
p.PG11, GenericSMI, mac_addr, 0,
|
||||
))
|
||||
let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
|
||||
|
||||
let device = unsafe {
|
||||
Ethernet::new(
|
||||
forever!(State::new()),
|
||||
p.ETH,
|
||||
eth_int,
|
||||
p.PA1,
|
||||
p.PA2,
|
||||
p.PC1,
|
||||
p.PA7,
|
||||
p.PC4,
|
||||
p.PC5,
|
||||
p.PG13,
|
||||
p.PB13,
|
||||
p.PG11,
|
||||
GenericSMI,
|
||||
mac_addr,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
let config = StaticConfigurator::new(NetConfig {
|
||||
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 0, 61), 24),
|
||||
dns_servers: Vec::new(),
|
||||
gateway: Some(Ipv4Address::new(192, 168, 0, 1)),
|
||||
});
|
||||
let config = embassy_net::ConfigStrategy::Dhcp;
|
||||
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
|
||||
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
|
||||
// dns_servers: Vec::new(),
|
||||
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
|
||||
//});
|
||||
|
||||
let config = CONFIG.put(config);
|
||||
// Init network stack
|
||||
let stack = &*forever!(Stack::new(
|
||||
device,
|
||||
config,
|
||||
forever!(StackResources::<1, 2, 8>::new()),
|
||||
seed
|
||||
));
|
||||
|
||||
let executor = EXECUTOR.put(Executor::new());
|
||||
// Launch network task
|
||||
unwrap!(spawner.spawn(net_task(&stack)));
|
||||
|
||||
executor.run(move |spawner| {
|
||||
unwrap!(spawner.spawn(main_task(eth, config, spawner)));
|
||||
})
|
||||
info!("Network task initialized");
|
||||
|
||||
// Then we can use it!
|
||||
let mut rx_buffer = [0; 1024];
|
||||
let mut tx_buffer = [0; 1024];
|
||||
|
||||
loop {
|
||||
let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
|
||||
|
||||
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
|
||||
|
||||
let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
|
||||
info!("connecting...");
|
||||
let r = socket.connect(remote_endpoint).await;
|
||||
if let Err(e) = r {
|
||||
info!("connect error: {:?}", e);
|
||||
continue;
|
||||
}
|
||||
info!("connected!");
|
||||
loop {
|
||||
let r = socket.write_all(b"Hello\n").await;
|
||||
if let Err(e) = r {
|
||||
info!("write error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user