Read multiple ADC channels (maybe)
At least this is compiling without errors now. - Added the ext_adc module abstracting the ADC communication (with the AdcContext struct). - SPI and necessary DMA channels are now passed into the AdcContext struct and moved around on each transfer. - Transfers seem to be triggered, but the returned values are still wrong (either 0 or 4095). This still needs to be debugged.
This commit is contained in:
parent
1a6e442815
commit
28bd3b20ab
80
src/ext_adc.rs
Normal file
80
src/ext_adc.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use cortex_m::singleton;
|
||||
use rp2040_hal::dma::{bidirectional, Channel};
|
||||
use fugit::HertzU32;
|
||||
use fugit::RateExtU32;
|
||||
|
||||
pub struct AdcContext<D, TXC, RXC, CSP>
|
||||
where
|
||||
TXC: rp2040_hal::dma::ChannelIndex,
|
||||
RXC: rp2040_hal::dma::ChannelIndex,
|
||||
D: rp2040_hal::spi::SpiDevice
|
||||
{
|
||||
dma_tx_chan: Channel<TXC>,
|
||||
dma_rx_chan: Channel<RXC>,
|
||||
tx_buf: &'static mut [u8; 3],
|
||||
rx_buf: &'static mut [u8; 3],
|
||||
spi: rp2040_hal::spi::Spi<rp2040_hal::spi::Enabled, D, 8>,
|
||||
cs_pin: CSP
|
||||
}
|
||||
|
||||
impl<D, TXC, RXC, E, CSP> AdcContext<D, TXC, RXC, CSP>
|
||||
where
|
||||
TXC: rp2040_hal::dma::ChannelIndex,
|
||||
RXC: rp2040_hal::dma::ChannelIndex,
|
||||
D: rp2040_hal::spi::SpiDevice,
|
||||
E: core::fmt::Debug,
|
||||
CSP: embedded_hal::digital::v2::OutputPin<Error=E>
|
||||
{
|
||||
pub fn init(
|
||||
device: D,
|
||||
periph_freq: HertzU32,
|
||||
resets: &mut rp2040_pac::RESETS,
|
||||
tx_chan: Channel<TXC>,
|
||||
rx_chan: Channel<RXC>,
|
||||
mut cs_pin: CSP
|
||||
) -> Self
|
||||
{
|
||||
let spi_if = rp2040_hal::spi::Spi::<_, _, 8>::new(device);
|
||||
|
||||
// Exchange the uninitialised SPI driver for an initialised one
|
||||
let spi_if = spi_if.init(
|
||||
resets,
|
||||
periph_freq,
|
||||
1_000_000u32.Hz(),
|
||||
&embedded_hal::spi::MODE_0,
|
||||
);
|
||||
|
||||
cs_pin.set_high().unwrap();
|
||||
|
||||
AdcContext::<D, TXC, RXC, CSP> {
|
||||
dma_rx_chan: rx_chan,
|
||||
dma_tx_chan: tx_chan,
|
||||
rx_buf: singleton!(: [u8; 3] = [0x06, 0x40, 0x00]).unwrap(),
|
||||
tx_buf: singleton!(: [u8; 3] = [0; 3]).unwrap(),
|
||||
spi: spi_if,
|
||||
cs_pin: cs_pin
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sample_adc_channel(mut self, chan: u8) -> (Self, u16)
|
||||
{
|
||||
self.tx_buf[1] = chan << 6;
|
||||
|
||||
// clear chip select
|
||||
self.cs_pin.set_low().unwrap();
|
||||
|
||||
// Use BidirectionalConfig to simultaneously write to spi from tx_buf and read into rx_buf
|
||||
let transfer = bidirectional::Config::new(
|
||||
(self.dma_tx_chan, self.dma_rx_chan),
|
||||
self.tx_buf,
|
||||
self.spi,
|
||||
self.rx_buf).start();
|
||||
|
||||
// Wait for both DMA channels to finish
|
||||
((self.dma_tx_chan, self.dma_rx_chan), self.tx_buf, self.spi, self.rx_buf) = transfer.wait();
|
||||
self.cs_pin.set_high().unwrap();
|
||||
|
||||
let result = (((self.rx_buf[1] & 0x0F) as u16) << 8) | self.rx_buf[2] as u16;
|
||||
(self, result)
|
||||
}
|
||||
}
|
71
src/main.rs
71
src/main.rs
|
@ -19,7 +19,7 @@ use panic_halt as _;
|
|||
use rp2040_hal as hal;
|
||||
|
||||
// Some traits we need
|
||||
use cortex_m::singleton;
|
||||
//use cortex_m::singleton;
|
||||
use embedded_hal::PwmPin;
|
||||
use fugit::RateExtU32;
|
||||
use rp2040_hal::clocks::Clock;
|
||||
|
@ -29,13 +29,15 @@ use rp2040_hal::clocks::Clock;
|
|||
use hal::pac;
|
||||
|
||||
// SPI + DMA
|
||||
use hal::dma::{bidirectional, DMAExt};
|
||||
use hal::dma::DMAExt;
|
||||
|
||||
// UART related types
|
||||
use hal::uart::{DataBits, StopBits, UartConfig};
|
||||
|
||||
use heapless::String;
|
||||
|
||||
mod ext_adc;
|
||||
|
||||
/// The linker will place this boot block at the start of our program image. We
|
||||
/// need this to help the ROM bootloader get our code up and running.
|
||||
/// Note: This boot block is not necessary when using a rp-hal based BSP
|
||||
|
@ -156,41 +158,19 @@ fn main() -> ! {
|
|||
let _spi_sclk = pins.gpio2.into_mode::<hal::gpio::FunctionSpi>();
|
||||
let _spi_mosi = pins.gpio3.into_mode::<hal::gpio::FunctionSpi>();
|
||||
let _spi_miso = pins.gpio4.into_mode::<hal::gpio::FunctionSpi>();
|
||||
let spi = hal::spi::Spi::<_, _, 8>::new(pac.SPI0);
|
||||
|
||||
// Exchange the uninitialised SPI driver for an initialised one
|
||||
let spi = spi.init(
|
||||
&mut pac.RESETS,
|
||||
clocks.peripheral_clock.freq(),
|
||||
1_000_000u32.Hz(),
|
||||
&embedded_hal::spi::MODE_0,
|
||||
);
|
||||
|
||||
// Initialize DMA.
|
||||
let dma = pac.DMA.split(&mut pac.RESETS);
|
||||
|
||||
// Use DMA to read ADC (0xC0 in byte 1 is the channel mask)
|
||||
let tx_buf = singleton!(: [u8; 3] = [0x06, 0x40, 0x00]).unwrap();
|
||||
let rx_buf = singleton!(: [u8; 3] = [0; 3]).unwrap();
|
||||
let mut adc_ctrl = ext_adc::AdcContext::init(
|
||||
pac.SPI0,
|
||||
clocks.peripheral_clock.freq(),
|
||||
&mut pac.RESETS,
|
||||
dma.ch0,
|
||||
dma.ch1,
|
||||
spi_cs
|
||||
);
|
||||
|
||||
// clear chip select
|
||||
spi_cs.set_low().unwrap();
|
||||
|
||||
// Use BidirectionalConfig to simultaneously write to spi from tx_buf and read into rx_buf
|
||||
let transfer = bidirectional::Config::new((dma.ch0, dma.ch1), tx_buf, spi, rx_buf).start();
|
||||
// Wait for both DMA channels to finish
|
||||
let ((_ch0, _ch1), tx_buf, _spi, rx_buf) = transfer.wait();
|
||||
spi_cs.set_high().unwrap();
|
||||
|
||||
let adc_value = (((rx_buf[1] & 0x0F) as u16) << 8) | rx_buf[2] as u16;
|
||||
|
||||
{
|
||||
let data: String<16> = String::from(adc_value);
|
||||
|
||||
uart.write_full_blocking(b"Read ADC value: ");
|
||||
uart.write_full_blocking(data.as_bytes());
|
||||
uart.write_full_blocking(b"\r\n");
|
||||
}
|
||||
|
||||
// Infinite loop, fading LED up and down
|
||||
loop {
|
||||
|
@ -205,5 +185,32 @@ fn main() -> ! {
|
|||
channel2.set_duty(ch_val[1]);
|
||||
channel3.set_duty(ch_val[2]);
|
||||
delay.delay_us(50);
|
||||
|
||||
let mut adc_value: [u16; 4] = [0; 4];
|
||||
|
||||
(adc_ctrl, adc_value[0]) = adc_ctrl.sample_adc_channel(0);
|
||||
delay.delay_us(50);
|
||||
(adc_ctrl, adc_value[1]) = adc_ctrl.sample_adc_channel(1);
|
||||
delay.delay_us(50);
|
||||
(adc_ctrl, adc_value[2]) = adc_ctrl.sample_adc_channel(2);
|
||||
delay.delay_us(50);
|
||||
(adc_ctrl, adc_value[3]) = adc_ctrl.sample_adc_channel(3);
|
||||
|
||||
{
|
||||
let mut data: String<16>;
|
||||
|
||||
uart.write_full_blocking(b"ADC channels: [");
|
||||
|
||||
for i in 0..adc_value.len() {
|
||||
data = String::from(adc_value[0]);
|
||||
uart.write_full_blocking(data.as_bytes());
|
||||
|
||||
if i < 3 {
|
||||
uart.write_full_blocking(b", ");
|
||||
}
|
||||
}
|
||||
|
||||
uart.write_full_blocking(b"]\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue