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;
|
use rp2040_hal as hal;
|
||||||
|
|
||||||
// Some traits we need
|
// Some traits we need
|
||||||
use cortex_m::singleton;
|
//use cortex_m::singleton;
|
||||||
use embedded_hal::PwmPin;
|
use embedded_hal::PwmPin;
|
||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
use rp2040_hal::clocks::Clock;
|
use rp2040_hal::clocks::Clock;
|
||||||
|
@ -29,13 +29,15 @@ use rp2040_hal::clocks::Clock;
|
||||||
use hal::pac;
|
use hal::pac;
|
||||||
|
|
||||||
// SPI + DMA
|
// SPI + DMA
|
||||||
use hal::dma::{bidirectional, DMAExt};
|
use hal::dma::DMAExt;
|
||||||
|
|
||||||
// UART related types
|
// UART related types
|
||||||
use hal::uart::{DataBits, StopBits, UartConfig};
|
use hal::uart::{DataBits, StopBits, UartConfig};
|
||||||
|
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
|
|
||||||
|
mod ext_adc;
|
||||||
|
|
||||||
/// The linker will place this boot block at the start of our program image. We
|
/// 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.
|
/// 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
|
/// 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_sclk = pins.gpio2.into_mode::<hal::gpio::FunctionSpi>();
|
||||||
let _spi_mosi = pins.gpio3.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_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.
|
// Initialize DMA.
|
||||||
let dma = pac.DMA.split(&mut pac.RESETS);
|
let dma = pac.DMA.split(&mut pac.RESETS);
|
||||||
|
|
||||||
// Use DMA to read ADC (0xC0 in byte 1 is the channel mask)
|
let mut adc_ctrl = ext_adc::AdcContext::init(
|
||||||
let tx_buf = singleton!(: [u8; 3] = [0x06, 0x40, 0x00]).unwrap();
|
pac.SPI0,
|
||||||
let rx_buf = singleton!(: [u8; 3] = [0; 3]).unwrap();
|
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
|
// Infinite loop, fading LED up and down
|
||||||
loop {
|
loop {
|
||||||
|
@ -205,5 +185,32 @@ fn main() -> ! {
|
||||||
channel2.set_duty(ch_val[1]);
|
channel2.set_duty(ch_val[1]);
|
||||||
channel3.set_duty(ch_val[2]);
|
channel3.set_duty(ch_val[2]);
|
||||||
delay.delay_us(50);
|
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