diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-09-09 20:03:28 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-09-09 20:03:28 +0000 |
| commit | 2286e5da13b11f0cfc37e5345e3ed3c40f774055 (patch) | |
| tree | 5afa31997e3dd024135151ce64813f5db478569b /examples | |
| parent | 0ef06cc19b61c8196fea941514ec313a0f15d145 (diff) | |
| parent | 6af1cb7a20fe15750b353e2e6af6832786f8c065 (diff) | |
Merge pull request #3105 from embassy-rs/net-nrf91
embassy-net driver for nrf91
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf9160/.cargo/config.toml | 3 | ||||
| -rw-r--r-- | examples/nrf9160/Cargo.toml | 6 | ||||
| -rw-r--r-- | examples/nrf9160/memory.x | 8 | ||||
| -rw-r--r-- | examples/nrf9160/src/bin/modem_tcp_client.rs | 204 |
4 files changed, 218 insertions, 3 deletions
diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml index f64c63966..6072b8595 100644 --- a/examples/nrf9160/.cargo/config.toml +++ b/examples/nrf9160/.cargo/config.toml | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 2 | runner = "probe-rs run --chip nRF9160_xxAA" | 2 | # runner = "probe-rs run --chip nRF9160_xxAA" |
| 3 | runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ] | ||
| 3 | 4 | ||
| 4 | [build] | 5 | [build] |
| 5 | target = "thumbv8m.main-none-eabihf" | 6 | target = "thumbv8m.main-none-eabihf" |
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index c30b54ebd..9aeb99317 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml | |||
| @@ -8,13 +8,19 @@ license = "MIT OR Apache-2.0" | |||
| 8 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 11 | embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } | ||
| 12 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } | ||
| 11 | 13 | ||
| 12 | defmt = "0.3" | 14 | defmt = "0.3" |
| 13 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
| 14 | 16 | ||
| 17 | heapless = "0.8" | ||
| 15 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 16 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 17 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | static_cell = { version = "2" } | ||
| 22 | embedded-io = "0.6.1" | ||
| 23 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | ||
| 18 | 24 | ||
| 19 | [profile.release] | 25 | [profile.release] |
| 20 | debug = 2 | 26 | debug = 2 |
diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x index 4c7d4ebf0..e33498773 100644 --- a/examples/nrf9160/memory.x +++ b/examples/nrf9160/memory.x | |||
| @@ -1,5 +1,9 @@ | |||
| 1 | MEMORY | 1 | MEMORY |
| 2 | { | 2 | { |
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K | 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K |
| 4 | RAM : ORIGIN = 0x20018000, LENGTH = 160K | 4 | RAM : ORIGIN = 0x20010000, LENGTH = 192K |
| 5 | IPC : ORIGIN = 0x20000000, LENGTH = 64K | ||
| 5 | } | 6 | } |
| 7 | |||
| 8 | PROVIDE(__start_ipc = ORIGIN(IPC)); | ||
| 9 | PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC)); | ||
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs new file mode 100644 index 000000000..5335b6b51 --- /dev/null +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | use core::net::IpAddr; | ||
| 6 | use core::ptr::addr_of_mut; | ||
| 7 | use core::slice; | ||
| 8 | use core::str::FromStr; | ||
| 9 | |||
| 10 | use defmt::{info, unwrap, warn}; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; | ||
| 13 | use embassy_net_nrf91::context::Status; | ||
| 14 | use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; | ||
| 15 | use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; | ||
| 16 | use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; | ||
| 17 | use embassy_nrf::uarte::Baudrate; | ||
| 18 | use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; | ||
| 19 | use embassy_time::{Duration, Timer}; | ||
| 20 | use embedded_io_async::Write; | ||
| 21 | use heapless::Vec; | ||
| 22 | use static_cell::StaticCell; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | #[interrupt] | ||
| 26 | fn IPC() { | ||
| 27 | embassy_net_nrf91::on_ipc_irq(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { | ||
| 36 | let mut rx = [0u8; 1024]; | ||
| 37 | loop { | ||
| 38 | let n = reader.read(&mut rx[..]).await; | ||
| 39 | unwrap!(uart.write_all(&rx[..n]).await); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | #[embassy_executor::task] | ||
| 44 | async fn modem_task(runner: Runner<'static>) -> ! { | ||
| 45 | runner.run().await | ||
| 46 | } | ||
| 47 | |||
| 48 | #[embassy_executor::task] | ||
| 49 | async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>) -> ! { | ||
| 50 | stack.run().await | ||
| 51 | } | ||
| 52 | |||
| 53 | #[embassy_executor::task] | ||
| 54 | async fn control_task( | ||
| 55 | control: &'static context::Control<'static>, | ||
| 56 | config: context::Config<'static>, | ||
| 57 | stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>, | ||
| 58 | ) { | ||
| 59 | unwrap!(control.configure(&config).await); | ||
| 60 | unwrap!( | ||
| 61 | control | ||
| 62 | .run(|status| { | ||
| 63 | stack.set_config_v4(status_to_config(status)); | ||
| 64 | }) | ||
| 65 | .await | ||
| 66 | ); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { | ||
| 70 | let Some(IpAddr::V4(addr)) = status.ip else { | ||
| 71 | panic!("Unexpected IP address"); | ||
| 72 | }; | ||
| 73 | let addr = Ipv4Address(addr.octets()); | ||
| 74 | |||
| 75 | let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { | ||
| 76 | Some(Ipv4Address(addr.octets())) | ||
| 77 | } else { | ||
| 78 | None | ||
| 79 | }; | ||
| 80 | |||
| 81 | let mut dns_servers = Vec::new(); | ||
| 82 | for dns in status.dns.iter() { | ||
| 83 | if let IpAddr::V4(ip) = dns { | ||
| 84 | unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { | ||
| 89 | address: Ipv4Cidr::new(addr, 32), | ||
| 90 | gateway, | ||
| 91 | dns_servers, | ||
| 92 | }) | ||
| 93 | } | ||
| 94 | |||
| 95 | #[embassy_executor::task] | ||
| 96 | async fn blink_task(pin: AnyPin) { | ||
| 97 | let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); | ||
| 98 | loop { | ||
| 99 | led.set_high(); | ||
| 100 | Timer::after_millis(1000).await; | ||
| 101 | led.set_low(); | ||
| 102 | Timer::after_millis(1000).await; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | extern "C" { | ||
| 107 | static __start_ipc: u8; | ||
| 108 | static __end_ipc: u8; | ||
| 109 | } | ||
| 110 | |||
| 111 | #[embassy_executor::main] | ||
| 112 | async fn main(spawner: Spawner) { | ||
| 113 | let p = embassy_nrf::init(Default::default()); | ||
| 114 | |||
| 115 | info!("Hello World!"); | ||
| 116 | |||
| 117 | unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); | ||
| 118 | |||
| 119 | let ipc_mem = unsafe { | ||
| 120 | let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit<u8>; | ||
| 121 | let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit<u8>; | ||
| 122 | let ipc_len = ipc_end.offset_from(ipc_start) as usize; | ||
| 123 | slice::from_raw_parts_mut(ipc_start, ipc_len) | ||
| 124 | }; | ||
| 125 | |||
| 126 | static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; | ||
| 127 | let mut config = uarte::Config::default(); | ||
| 128 | config.baudrate = Baudrate::BAUD1M; | ||
| 129 | let uart = BufferedUarteTx::new( | ||
| 130 | //let trace_uart = BufferedUarteTx::new( | ||
| 131 | unsafe { peripherals::SERIAL0::steal() }, | ||
| 132 | Irqs, | ||
| 133 | unsafe { peripherals::P0_01::steal() }, | ||
| 134 | //unsafe { peripherals::P0_14::steal() }, | ||
| 135 | config, | ||
| 136 | unsafe { &mut *addr_of_mut!(TRACE_BUF) }, | ||
| 137 | ); | ||
| 138 | |||
| 139 | static STATE: StaticCell<State> = StaticCell::new(); | ||
| 140 | static TRACE: StaticCell<TraceBuffer> = StaticCell::new(); | ||
| 141 | let (device, control, runner, tracer) = | ||
| 142 | embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await; | ||
| 143 | unwrap!(spawner.spawn(modem_task(runner))); | ||
| 144 | unwrap!(spawner.spawn(trace_task(uart, tracer))); | ||
| 145 | |||
| 146 | let config = embassy_net::Config::default(); | ||
| 147 | |||
| 148 | // Generate "random" seed. nRF91 has no RNG, TODO figure out something... | ||
| 149 | let seed = 123456; | ||
| 150 | |||
| 151 | // Init network stack | ||
| 152 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | ||
| 153 | static STACK: StaticCell<Stack<embassy_net_nrf91::NetDriver<'static>>> = StaticCell::new(); | ||
| 154 | let stack = &*STACK.init(Stack::new( | ||
| 155 | device, | ||
| 156 | config, | ||
| 157 | RESOURCES.init(StackResources::<2>::new()), | ||
| 158 | seed, | ||
| 159 | )); | ||
| 160 | |||
| 161 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 162 | |||
| 163 | static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new(); | ||
| 164 | let control = CONTROL.init(context::Control::new(control, 0).await); | ||
| 165 | |||
| 166 | unwrap!(spawner.spawn(control_task( | ||
| 167 | control, | ||
| 168 | context::Config { | ||
| 169 | apn: b"iot.nat.es", | ||
| 170 | auth_prot: context::AuthProt::Pap, | ||
| 171 | auth: Some((b"orange", b"orange")), | ||
| 172 | }, | ||
| 173 | stack | ||
| 174 | ))); | ||
| 175 | |||
| 176 | stack.wait_config_up().await; | ||
| 177 | |||
| 178 | let mut rx_buffer = [0; 4096]; | ||
| 179 | let mut tx_buffer = [0; 4096]; | ||
| 180 | loop { | ||
| 181 | let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 182 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 183 | |||
| 184 | info!("Connecting..."); | ||
| 185 | let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); | ||
| 186 | if let Err(e) = socket.connect((host_addr, 4242)).await { | ||
| 187 | warn!("connect error: {:?}", e); | ||
| 188 | Timer::after_secs(10).await; | ||
| 189 | continue; | ||
| 190 | } | ||
| 191 | info!("Connected to {:?}", socket.remote_endpoint()); | ||
| 192 | |||
| 193 | let msg = b"Hello world!\n"; | ||
| 194 | for _ in 0..10 { | ||
| 195 | if let Err(e) = socket.write_all(msg).await { | ||
| 196 | warn!("write error: {:?}", e); | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | info!("txd: {}", core::str::from_utf8(msg).unwrap()); | ||
| 200 | Timer::after_secs(1).await; | ||
| 201 | } | ||
| 202 | Timer::after_secs(4).await; | ||
| 203 | } | ||
| 204 | } | ||
