diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 830a5b44..7316466f 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -177,7 +177,10 @@ where let read_bits = read.len() * 32 + 32 - 1; #[cfg(feature = "defmt")] - defmt::trace!("write={} read={}", write_bits, read_bits); + defmt::trace!("cmd_read write={} read={}", write_bits, read_bits); + + #[cfg(feature = "defmt")] + defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len()); unsafe { pio_instr_util::set_y(&mut self.sm, read_bits as u32); @@ -197,6 +200,10 @@ where .rx() .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) .await; + + #[cfg(feature = "defmt")] + defmt::trace!("cmd_read cmd = {:02x} len = {} read = {:08x}", cmd, read.len(), read); + status } } diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs index b7f2c318..35a1bfdf 100644 --- a/cyw43/src/bluetooth.rs +++ b/cyw43/src/bluetooth.rs @@ -21,21 +21,20 @@ pub(crate) async fn upload_bluetooth_firmware( // buffer let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100]; // structs - let mut pointer = 0; + let mut fw_bytes_pointer = 0; for (index, &(dest_addr, num_fw_bytes)) in firmware_offsets.iter().enumerate() { - let fw_bytes = &firmware[(pointer)..(pointer + num_fw_bytes)]; + let fw_bytes = &firmware[(fw_bytes_pointer)..(fw_bytes_pointer + num_fw_bytes)]; assert!(fw_bytes.len() == num_fw_bytes); - //debug!("index = {}/{} dest_addr = {:08x} num_fw_bytes = {} fw_bytes = {:02x}", index, firmware_offsets.len(), dest_addr, num_fw_bytes, fw_bytes); - //debug!("index = {}/{} dest_addr = {:08x} num_fw_bytes = {} pointer = {}", index, firmware_offsets.len(), dest_addr, num_fw_bytes, pointer); + debug!("index = {}/{} dest_addr = {:08x} num_fw_bytes = {} fw_bytes_pointer = {} fw_bytes = {:02x}", index, firmware_offsets.len(), dest_addr, num_fw_bytes, fw_bytes_pointer, fw_bytes); let mut dest_start_addr = dest_addr; let mut aligned_data_buffer_index: usize = 0; // pad start if !is_aligned(dest_start_addr, 4) { let num_pad_bytes = dest_start_addr % 4; let padded_dest_start_addr = round_down(dest_start_addr, 4); - let mut memory_value_bytes = [0; 4]; - bus.bp_read(padded_dest_start_addr, &mut memory_value_bytes).await; - //debug!("pad start padded_dest_start_addr = {:08x} memory_value_bytes = {:02x}", padded_dest_start_addr, memory_value_bytes); + let memory_value = bus.bp_read32(padded_dest_start_addr).await; + let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be + debug!("pad start padded_dest_start_addr = {:08x} memory_value_bytes = {:02x}", padded_dest_start_addr, memory_value_bytes); // Copy the previous memory value's bytes to the start for i in 0..num_pad_bytes as usize { aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i]; @@ -60,9 +59,9 @@ pub(crate) async fn upload_bluetooth_firmware( let offset = dest_end_addr % 4; let num_pad_bytes_end = 4 - offset; let padded_dest_end_addr = round_down(dest_end_addr, 4); - let mut memory_value_bytes = [0; 4]; - bus.bp_read(padded_dest_end_addr, &mut memory_value_bytes).await; - //debug!("pad end padded_dest_end_addr = {:08x} memory_value_bytes = {:02x}", padded_dest_end_addr, memory_value_bytes); + let memory_value = bus.bp_read32(padded_dest_end_addr).await; + let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be + debug!("pad end padded_dest_end_addr = {:08x} memory_value_bytes = {:02x}", padded_dest_end_addr, memory_value_bytes); // Append the necessary memory bytes to pad the end of aligned_data_buffer for i in offset..4 { aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize]; @@ -77,9 +76,16 @@ pub(crate) async fn upload_bluetooth_firmware( assert!(dest_start_addr % 4 == 0); assert!(dest_end_addr % 4 == 0); assert!(aligned_data_buffer_index % 4 == 0); - bus.bp_write(dest_start_addr, buffer_to_write).await; - // increment pointer - pointer += num_fw_bytes; + // write in 0x40 chunks TODO: is this needed + let chunk_size = 0x40; + for (i, chunk) in buffer_to_write.chunks(chunk_size).enumerate() { + let offset = i * chunk_size; + bus.bp_write(dest_start_addr + (offset as u32), chunk).await; + } + // increment fw_bytes_pointer + fw_bytes_pointer += num_fw_bytes; + // sleep TODO: is this needed + Timer::after(Duration::from_millis(1)).await; } } @@ -90,30 +96,29 @@ pub(crate) async fn wait_bt_ready(bus: &mut Bu let val = bus.bp_read32(BT_CTRL_REG_ADDR).await; // TODO: do we need to swap endianness on this read? debug!("BT_CTRL_REG_ADDR = {:08x}", val); - /*if val & BTSDIO_REG_FW_RDY_BITMASK != 0 { - break; - }*/ - // TODO: should be 00000000 until it is 0x01000100 - if val == 0x01000100 { + if val & BTSDIO_REG_FW_RDY_BITMASK != 0 { success = true; break; } - Timer::after(Duration::from_millis(100)).await; + Timer::after(Duration::from_millis(1)).await; } assert!(success == true); } pub(crate) async fn wait_bt_awake(bus: &mut Bus) { - debug!("wait_bt_awake"); - loop { + debug!("wait_bt_awake"); + let mut success = false; + for _ in 0..300 { let val = bus.bp_read32(BT_CTRL_REG_ADDR).await; // TODO: do we need to swap endianness on this read? debug!("BT_CTRL_REG_ADDR = {:08x}", val); if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 { + success = true; break; } - Timer::after(Duration::from_millis(100)).await; + Timer::after(Duration::from_millis(1)).await; } + assert!(success == true); } pub(crate) async fn bt_set_host_ready(bus: &mut Bus) { @@ -150,8 +155,12 @@ pub(crate) async fn bt_set_intr(bus: &mut Bus< } pub(crate) async fn init_bluetooth(bus: &mut Bus, firmware_offsets: &[(u32, usize)], firmware: &[u8]) { + Timer::after(Duration::from_millis(100)).await; + debug!("init_bluetooth"); + Timer::after(Duration::from_millis(100)).await; bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE) .await; + Timer::after(Duration::from_millis(2)).await; upload_bluetooth_firmware(bus, firmware_offsets, firmware).await; wait_bt_ready(bus).await; // TODO: cybt_init_buffer(); diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs index 46352692..abe0f2cb 100644 --- a/cyw43/src/bus.rs +++ b/cyw43/src/bus.rs @@ -50,34 +50,35 @@ where pub async fn init(&mut self) { // Reset - debug!("WL_REG off/on"); + defmt::debug!("WL_REG off/on"); self.pwr.set_low().unwrap(); Timer::after(Duration::from_millis(20)).await; self.pwr.set_high().unwrap(); Timer::after(Duration::from_millis(250)).await; - debug!("read REG_BUS_TEST_RO"); + defmt::debug!("read REG_BUS_TEST_RO"); while self - .read32_swapped(REG_BUS_TEST_RO) + .read32_swapped(FUNC_BUS, REG_BUS_TEST_RO) .inspect(|v| trace!("{:#x}", v)) .await != FEEDBEAD {} - debug!("write REG_BUS_TEST_RW"); - self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; - let val = self.read32_swapped(REG_BUS_TEST_RW).await; + defmt::debug!("write REG_BUS_TEST_RW"); + self.write32_swapped(FUNC_BUS, REG_BUS_TEST_RW, TEST_PATTERN).await; + let val = self.read32_swapped(FUNC_BUS, REG_BUS_TEST_RW).await; trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); - debug!("read REG_BUS_CTRL"); - let val = self.read32_swapped(REG_BUS_CTRL).await; + defmt::debug!("read REG_BUS_CTRL"); + let val = self.read32_swapped(FUNC_BUS, REG_BUS_CTRL).await; trace!("{:#010b}", (val & 0xff)); // 32-bit word length, little endian (which is the default endianess). // TODO: C library is uint32_t val = WORD_LENGTH_32 | HIGH_SPEED_MODE| ENDIAN_BIG | INTERRUPT_POLARITY_HIGH | WAKE_UP | 0x4 << (8 * SPI_RESPONSE_DELAY) | INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE); - debug!("write REG_BUS_CTRL"); + defmt::debug!("write REG_BUS_CTRL"); self.write32_swapped( + FUNC_BUS, REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED @@ -88,30 +89,29 @@ where ) .await; - debug!("read REG_BUS_CTRL"); + defmt::debug!("read REG_BUS_CTRL"); let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; trace!("{:#b}", val); // TODO: C doesn't do this? i doubt it messes anything up - debug!("read REG_BUS_TEST_RO"); + defmt::debug!("read REG_BUS_TEST_RO"); let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; trace!("{:#x}", val); assert_eq!(val, FEEDBEAD); // TODO: C doesn't do this? i doubt it messes anything up - debug!("read REG_BUS_TEST_RW"); + defmt::debug!("read REG_BUS_TEST_RW"); let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); - // TODO: setting this causes total failure (watermark read test fails) - debug!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES"); + defmt::debug!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES"); self.write8(FUNC_BUS, SPI_RESP_DELAY_F1, WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE) .await; // TODO: Make sure error interrupt bits are clear? // cyw43_write_reg_u8(self, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR | F1_OVERFLOW) != 0) - debug!("Make sure error interrupt bits are clear"); + defmt::debug!("Make sure error interrupt bits are clear"); self.write8( FUNC_BUS, REG_BUS_INTERRUPT, @@ -121,7 +121,7 @@ where // Enable a selection of interrupts // TODO: why not all of these F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW | COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE | F1_OVERFLOW | F1_INTR - debug!("enable a selection of interrupts"); + defmt::debug!("enable a selection of interrupts"); self.write16( FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, @@ -244,28 +244,45 @@ where } async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { + defmt::debug!("backplane_readn addr = {:08x} len = {}", addr, len); + self.backplane_set_window(addr).await; let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG; } - self.readn(FUNC_BACKPLANE, bus_addr, len).await + + let val = self.readn(FUNC_BACKPLANE, bus_addr, len).await; + + defmt::debug!("backplane_readn addr = {:08x} len = {} val = {:08x}", addr, len, val); + + self.backplane_set_window(0x18000000).await; // CHIPCOMMON_BASE_ADDRESS + + return val } async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { + defmt::debug!("backplane_writen addr = {:08x} len = {} val = {:08x}", addr, len, val); + self.backplane_set_window(addr).await; let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG; } - self.writen(FUNC_BACKPLANE, bus_addr, val, len).await + self.writen(FUNC_BACKPLANE, bus_addr, val, len).await; + + self.backplane_set_window(0x18000000).await; // CHIPCOMMON_BASE_ADDRESS } async fn backplane_set_window(&mut self, addr: u32) { let new_window = addr & !BACKPLANE_ADDRESS_MASK; + if new_window == self.backplane_window { + return; + } + if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 { self.write8( FUNC_BACKPLANE, @@ -290,6 +307,7 @@ where ) .await; } + self.backplane_window = new_window; } @@ -327,6 +345,8 @@ where self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await; + defmt::debug!("readn cmd = {:08x} addr = {:08x} len = {} buf = {:08x}", cmd, addr, len, buf); + // if we read from the backplane, the result is in the second word, after the response delay if func == FUNC_BACKPLANE { buf[1] @@ -341,8 +361,8 @@ where self.status = self.spi.cmd_write(&[cmd, val]).await; } - async fn read32_swapped(&mut self, addr: u32) -> u32 { - let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); + async fn read32_swapped(&mut self, func: u32, addr: u32) -> u32 { + let cmd = cmd_word(READ, INC_ADDR, func, addr, 4); let cmd = swap16(cmd); let mut buf = [0; 1]; @@ -351,7 +371,7 @@ where swap16(buf[0]) } - async fn write32_swapped(&mut self, addr: u32, val: u32) { + async fn write32_swapped(&mut self, func: u32, addr: u32, val: u32) { let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); let buf = [swap16(cmd), swap16(val)]; diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 94f63982..84975f53 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -214,8 +214,8 @@ pub async fn new<'a, PWR, SPI>( pwr: PWR, spi: SPI, firmware: &[u8], - bluetooth_firmware_offsets: &[(u32, usize)], - bluetooth_firmware: &[u8], + bluetooth_firmware_offsets: Option<&[(u32, usize)]>, + bluetooth_firmware: Option<&[u8]>, ) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) where PWR: OutputPin, diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 05ef1294..9858ca99 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -73,7 +73,7 @@ where } } - pub(crate) async fn init(&mut self, firmware: &[u8], bluetooth_firmware_offsets: &[(u32, usize)], bluetooth_firmware: &[u8]) { + pub(crate) async fn init(&mut self, firmware: &[u8], bluetooth_firmware_offsets: Option<&[(u32, usize)]>, bluetooth_firmware: Option<&[u8]>) { self.bus.init().await; // Init ALP (Active Low Power) clock @@ -116,8 +116,11 @@ where debug!("loading fw"); self.bus.bp_write(ram_addr, firmware).await; - debug!("loading bluetooth fw"); - bluetooth::init_bluetooth(&mut self.bus, bluetooth_firmware_offsets, bluetooth_firmware).await; + // Optionally load Bluetooth fimrware into RAM. + if bluetooth_firmware_offsets.is_some() && bluetooth_firmware.is_some() { + debug!("loading bluetooth fw"); + bluetooth::init_bluetooth(&mut self.bus, bluetooth_firmware_offsets.unwrap(), bluetooth_firmware.unwrap()).await; + } debug!("loading nvram"); // Round up to 4 bytes. diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index ad3cb72c..8b5d18e8 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -22,7 +22,7 @@ lorawan-device = { version = "0.10.0", default-features = false, features = ["as lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-firmware = { path = "../../cyw43-firmware" } -cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } +cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/src/bin/bluetooth_blinky.rs b/examples/rp/src/bin/bluetooth_blinky.rs new file mode 100644 index 00000000..19027484 --- /dev/null +++ b/examples/rp/src/bin/bluetooth_blinky.rs @@ -0,0 +1,70 @@ +//! This example test the RP Pico W on board LED. +//! +//! It does not work with the RP Pico board. See blinky.rs. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use cyw43_pio::PioSpi; +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_time::{Duration, Timer}; +use static_cell::make_static; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::task] +async fn cyw43_runner_task( + runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, +) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); + + // To make flashing faster for development, you may want to flash the firmwares independently + // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + + let pwr = Output::new(p.PIN_23, Level::Low); + let cs = Output::new(p.PIN_25, Level::High); + let mut pio = Pio::new(p.PIO0, Irqs); + let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + + let state = make_static!(cyw43::State::new()); + let bluetooth_firmware_offsets = &cyw43_firmware::BLUETOOTH_FIRMWARE_OFFSETS; + let bluetooth_firmware = &cyw43_firmware::BLUETOOTH_FIRMWARE; + let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw, Some(bluetooth_firmware_offsets), Some(bluetooth_firmware)).await; + unwrap!(spawner.spawn(cyw43_runner_task(runner))); + + control.init(clm).await; + control + .set_power_management(cyw43::PowerManagementMode::PowerSave) + .await; + + let delay = Duration::from_secs(1); + loop { + info!("led on!"); + control.gpio_set(0, true).await; + Timer::after(delay).await; + + info!("led off!"); + control.gpio_set(0, false).await; + Timer::after(delay).await; + } +} \ No newline at end of file diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 5203f6e3..51be50a0 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -31,8 +31,6 @@ async fn wifi_task( #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let bluetooth_firmware_offsets = &cyw43_firmware::BLUETOOTH_FIRMWARE_OFFSETS; - let bluetooth_firmware = &cyw43_firmware::BLUETOOTH_FIRMWARE; let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); @@ -49,7 +47,7 @@ async fn main(spawner: Spawner) { let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); let state = make_static!(cyw43::State::new()); - let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw, bluetooth_firmware_offsets, bluetooth_firmware).await; + let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; unwrap!(spawner.spawn(wifi_task(runner))); control.init(clm).await; @@ -67,4 +65,4 @@ async fn main(spawner: Spawner) { control.gpio_set(0, false).await; Timer::after(delay).await; } -} +} \ No newline at end of file