diff --git a/Cargo.lock b/Cargo.lock index d3f2093..88defec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,10 @@ dependencies = [ "litrs", ] +[[package]] +name = "eb_cmds" +version = "0.1.0" + [[package]] name = "embassy-executor" version = "0.5.0" @@ -603,7 +607,9 @@ dependencies = [ "defmt", "defmt-itm", "defmt-rtt", + "eb_cmds", "embassy-executor", + "embassy-sync", "embassy-usb", "futures", "u5-lib", diff --git a/Cargo.toml b/Cargo.toml index 1b7bf85..78f0b23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ cortex-m = { version = "0.7.7", features = [ u5-lib = { path = "../u5_new",features = [ "stm32u5a5qj", # "stm32u575zi" - ]} + ], default-features = false } +eb_cmds = { path = "../ebutton_usb_cmds"} critical-section = "1.1.2" defmt = "0.3.6" defmt-rtt = { version = "0.4.0" } @@ -29,6 +30,7 @@ futures = { version = "0.3.17", default-features = false, fetures = [ ]} cortex-m-rt = { version = "0.7.3" } + [dependencies.embassy-usb] git = "https://github.com/embassy-rs/embassy" rev = "35f284e" @@ -38,11 +40,19 @@ features = ["nightly", "arch-cortex-m", "executor-thread"] git = "https://github.com/embassy-rs/embassy" rev = "35f284e" +[dependencies.embassy-sync] +git = "https://github.com/embassy-rs/embassy" +rev = "35f284e" + + + + + # [dependencies.stm32-metapac] # path = "../stm32-data/build/stm32-metapac" # features = [ "memory-x", "rt"] # disable all optimizations [profile.dev] -opt-level = 0 +opt-level = 1 debug = true \ No newline at end of file diff --git a/src/bin/i2c.rs b/src/bin/i2c.rs index a27615c..ec4b612 100644 --- a/src/bin/i2c.rs +++ b/src/bin/i2c.rs @@ -31,7 +31,7 @@ fn main() -> ! { #[task] async fn async_main(_spawner: Spawner) { - clock::init_clock(true, false, clock::ClockFreqs::KernelFreq160Mhz); + clock::init_clock(true, true, false, clock::ClockFreqs::KernelFreq160Mhz); BLUE.setup(); defmt::info!("setup led finished!"); loop { diff --git a/src/main.rs b/src/main.rs index a2dca4b..56d9235 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,17 +8,21 @@ use core::panic::PanicInfo; use cortex_m::asm::delay; use defmt_rtt as _; -use embassy_executor::{Spawner}; +use eb_cmds::Command; +use embassy_executor::Spawner; use embassy_usb::{ - Builder, class::cdc_acm::{CdcAcmClass, State}, driver::EndpointError, + Builder, }; -use futures::future::{join}; +use futures::future::join; -use u5_lib::{gpio::{SDMMC2_CMD_PD7, SDMMC2_D0_PB14}, *}; use u5_lib::clock::delay_ms; use u5_lib::com_interface::ComInterface; +use u5_lib::{ + gpio::{SDMMC2_CMD_PD7, SDMMC2_D0_PB14}, + *, +}; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { @@ -32,16 +36,21 @@ fn panic(_info: &PanicInfo) -> ! { loop {} } - fn setup_camera() -> (gpio::GpioPort, i2c::I2c) { - clock::set_mco(gpio::GPIO_MCO_PA8, clock::Mcosel::HSI, clock::Mcopre::DIV1); // clock. which use PA8 as clock output + clock::set_mco(gpio::GPIO_MCO_PA8, clock::Mcosel::HSI, clock::Mcopre::DIV1); // clock. which use PA8 as clock output let cam_down = gpio::PD13; cam_down.setup(); cam_down.set_high(); cam_down.set_low(); // wait for short time delay_ms(50); - let mut i2c = i2c::I2c::new(i2c::I2cConfig::new(2, 100_000, gpio::I2C2_SDA_PF0, gpio::I2C2_SCL_PF1)).unwrap(); + let mut i2c = i2c::I2c::new(i2c::I2cConfig::new( + 2, + 100_000, + gpio::I2C2_SDA_PF0, + gpio::I2C2_SCL_PF1, + )) + .unwrap(); // delay_ms(1); camera::setup_camera(&mut i2c); (cam_down, i2c) @@ -52,56 +61,123 @@ fn setup_led() -> gpio::GpioPort { green.setup(); green } + fn setup_sd() -> sdmmc::SdInstance { - let mut sd = sdmmc::SdInstance::new( sdmmc::SDMMC2); + let mut sd = sdmmc::SdInstance::new(sdmmc::SDMMC2); sd.init(gpio::SDMMC2_CK_PD6, SDMMC2_CMD_PD7, SDMMC2_D0_PB14); sd } +fn set_dcmi() -> dcmi::DcmiPort { + let dcmi = dcmi::DCMI; + + dcmi.init( + gpio::DCMI_D0_PA9, // todo: updat the pin + gpio::DCMI_D1_PA10, + gpio::DCMI_D2_PE0, + gpio::DCMI_D3_PE1, + gpio::DCMI_D4_PE4, + gpio::DCMI_D5_PB6, + gpio::DCMI_D6_PE5, + gpio::DCMI_D7_PE6, + gpio::DCMI_HSYNC_PA4, + gpio::DCMI_VSYNC_PB7, + gpio::DCMI_PIXCLK_PD9, + ); + dcmi +} + // #[embassy_executor::main] #[task] async fn async_main(spawner: Spawner) { // clock::init_clock(true, false, clock::ClockFreqs::KernelFreq4Mhz); - clock::init_clock(false, true, clock::ClockFreqs::KernelFreq160Mhz); - // let (cam_down, i2c) = setup_camera(); + clock::init_clock(false, true, true, clock::ClockFreqs::KernelFreq160Mhz); // cam_down.set_high(); delay_ms(200); defmt::info!("camera init finished!"); - let sd = setup_sd(); defmt::info!("sd init finished!"); let green = setup_led(); spawner.spawn(btn()).unwrap(); spawner.spawn(pwr::vddusb_monitor_up()).unwrap(); spawner.spawn(usb_task()).unwrap(); - // start emmc + // init dcmi + let (cam_down, mut i2c, sd, dcmi) = + clock::hclk_request(clock::ClockFreqs::KernelFreq160Mhz, || { + let (cam_down, i2c) = setup_camera(); + let sd = setup_sd(); + let dcmi = set_dcmi(); + (cam_down, i2c, sd, dcmi) + }); defmt::info!("usb init finished!"); + let mut power_on = false; loop { - exti::EXTI2_PB2.wait_for_raising().await; + if !power_on { + let val = POWER_SIGNAL.wait().await; + if val { + defmt::info!("power on"); + power_on = true; + } + } else { + if POWER_SIGNAL.signaled() { + let val = POWER_SIGNAL.wait().await; + power_on = val; + } + } + if !power_on { + continue; + } + + // exti::EXTI2_PB2.wait_for_raising().await; + // clock::init_clock(false, true, clock::ClockFreqs::KernelFreq160Mhz); + // clock::set_mco(gpio::GPIO_MCO_PA8, clock::Mcosel::HSI, clock::Mcopre::DIV1); // clock. which use PA8 as clock output + // delay_ms(1); + // rtc::rtc_interrupt().await; green.toggle(); - defmt::info!("exti2 triggered"); - unsafe {defmt::info!("deep sleep flag: {}", low_power::REF_COUNT_DEEP);} + let mut pic_buf = [0u8; 700_000]; + // deep sleep is not allowed + clock::hclk_request_async(clock::ClockFreqs::KernelFreq160Mhz, || async { + low_power::run_no_deep_sleep_async(|| async { + camera::capture(&cam_down, &mut i2c, &dcmi, &mut pic_buf).await; + camera::save_picture(&mut pic_buf, &sd).await; + defmt::info!("finish save picture, ########################"); + }) + .await; + }) + .await; } } use low_power::Executor; + #[cortex_m_rt::entry] fn main() -> ! { Executor::take().run(|spawner| { - // unwrap!(spawner.spawn(async_main(spawner))); spawner.spawn(async_main(spawner)).unwrap(); }); } +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::signal::Signal; +// static mut POWER_STATE: bool = false; +static POWER_SIGNAL: Signal = Signal::new(); #[embassy_executor::task] async fn btn() { let _last_time: (u8, u8, u8) = (0, 0, 0); defmt::info!("waiting for btn"); - loop { - exti::EXTI13_PC13.wait_for_raising().await; + unsafe { + static mut POWER_STATE: bool = false; + loop { + exti::EXTI2_PB2.wait_for_raising().await; + defmt::info!("btn pressed"); + let green: gpio::GpioPort = gpio::PD14; + green.toggle(); + POWER_STATE = !POWER_STATE; + POWER_SIGNAL.signal(POWER_STATE); + } } } @@ -169,23 +245,112 @@ impl From for Disconnected { } } +// todo: these should be rewrite +const IMG_START_BLOCK: u32 = 10; +const IMG_SIZE: u32 = 2000; +// 2000 block = 2000 * 512 = 1M +const SIZE_BLOCK: u32 = 1; // first block store the number of image files + async fn usb_handler<'d>(class: &mut CdcAcmClass<'d, usb_otg::Driver>) -> Result<(), Disconnected> { - let mut buf: [u8; 128] = [0; 128]; + let mut in_buf: [u8; 128] = [0; 128]; // the maximum size of the command is 64 bytes + + let sd = setup_sd(); defmt::info!("start usb handler"); loop { // select(future1, future2) - let ret = class.read_packet(&mut buf).await; - match ret { - Ok(n) => { - defmt::info!("read {} bytes", n); - class.write_packet(&buf[0..n]).await.unwrap(); + let ret = class.read_packet(&mut in_buf).await; + let n = match ret { + Ok(n) => n, + Err(EndpointError::Disabled) => return Err(Disconnected {}), + Err(EndpointError::BufferOverflow) => panic!("Buffer overflow"), + }; + + let command = eb_cmds::Command::from_array(&in_buf[..n]); + match command { + Command::SetTim(year, month, day, hour, minute, second, period) => { + // rtc::set_time(year, month, day, hour, minute, second, period); + rtc::setup(year, month, day, hour, minute, second, period, rtc::RtcSource::LSE); + let response = eb_cmds::Response::SetTim(0); + let (buf, len) = response.to_array(); + class.write_packet(&buf[..len]).await.unwrap(); } - Err(e) => { - defmt::info!("error: {:?}", e); - return Err(e.into()); + Command::GetTim => { + let date = rtc::get_date(); + let time = rtc::get_time(); + let response = eb_cmds::Response::GetTim(date.0, date.1, date.2, time.0, time.1, time.2); + let (buf, len) = response.to_array(); + class.write_packet(&buf[..len]).await.unwrap(); } + Command::GetPic(id) => { + let mut buf = [0; 64]; + buf[0] = 0x02; + let mut pic_buf = [0; 512]; + let start_block = (id + IMG_START_BLOCK) * IMG_SIZE; + sd.read_single_block_async(&mut pic_buf, start_block).await.unwrap(); + // get the end of picture + let pic_end = ((pic_buf[0] as u32) << 24) + | ((pic_buf[1] as u32) << 16) + | ((pic_buf[2] as u32) << 8) + | (pic_buf[3] as u32); + let block_count: u32 = ((pic_end + 512 - 1) / 512) as u32; + let mut ordinal = 0; + let mut send_len: usize; + let mut res: eb_cmds::Response; + let mut start = 16; + loop { + if start >= pic_buf.len() { + break; + } + (ordinal, send_len, res) = + eb_cmds::Response::pic_res_from_data(id, ordinal, &pic_buf[start..]); + if send_len == 0 { + break; + } + start += send_len; + + let (buf_tmp, len) = res.to_array(); + class.write_packet(&buf_tmp[0..len]).await.unwrap(); + // Timer::after(Duration::from_millis(100)).await; + // LED_BLUE.toggle(); + } + // LED_GREEN.toggle(); + for block in 1..block_count { + // sd.read_single_block(&mut buf, start_block + block).unwrap(); + // let mut pic_buf = [0; 512]; // why without this line, the program not work? + sd.read_single_block_async(&mut pic_buf, start_block + block).await.unwrap(); + start = 0; + loop { + if start >= pic_buf.len() { + break; + } + (ordinal, send_len, res) = + eb_cmds::Response::pic_res_from_data(id, ordinal, &pic_buf[start..]); + if send_len == 0 { + break; + } + start += send_len; + let (buf_tmp, len) = res.to_array(); + class.write_packet(&buf_tmp[0..len]).await.unwrap(); + } + } + } + Command::GetPicNum => { + let mut buf = [0u8; 512]; + sd.read_single_block_async(&mut buf, SIZE_BLOCK).await.unwrap(); + let num = ((buf[0] as u32) << 24) + | ((buf[1] as u32) << 16) + | ((buf[2] as u32) << 8) + | (buf[3] as u32); + // ebcmd::Response::GetPicNum(num) + let res = eb_cmds::Response::GetPicNum(num); + let (buf, len) = res.to_array(); + class.write_packet(&buf[0..len]).await.unwrap(); + } + Command::ClearPic => {} } + + // let ret = select(class.read_packet(&mut buf), class.write_packet(&buf)).await; // class.write_packet(&buf[0..n]).await.unwrap(); } }