Skip to content

Commit

Permalink
[rp2040] Basic ADC support
Browse files Browse the repository at this point in the history
  • Loading branch information
cocasema committed Aug 16, 2022
1 parent 3ad2bb4 commit 6b9ef11
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git

## Microcontrollers

modm can create a HAL for <!--allcount-->3287<!--/allcount--> devices of these vendors:
modm can create a HAL for <!--allcount-->3304<!--/allcount--> devices of these vendors:

- STMicroelectronics STM32: <!--stmcount-->2712<!--/stmcount--> devices.
- STMicroelectronics STM32: <!--stmcount-->2729<!--/stmcount--> devices.
- Microchip SAM: <!--samcount-->186<!--/samcount--> devices.
- Microchip AVR: <!--avrcount-->388<!--/avrcount--> devices.
- Raspberry Pi: <!--rpicount-->1<!--/rpicount--> device.
Expand Down Expand Up @@ -144,7 +144,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">○</td>
<td align="center">✅</td>
<td align="center">○</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">○</td>
<td align="center">✅</td>
<td align="center">✅</td>
Expand Down
57 changes: 57 additions & 0 deletions examples/rp_pico/adc_simple/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2022, Nikolay Semenov
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/io/iostream.hpp>
#include <modm/platform.hpp>

int
main()
{
Board::initialize();

using Led = Board::LedGreen;
Led::setOutput(true);

Uart0::connect<GpioOutput0::Tx>();
Uart0::initialize<Board::SystemClock, 115200_Bd>();

modm::IODeviceWrapper<Uart0, modm::IOBuffer::BlockIfFull> loggerDevice;
modm::IOStream out(loggerDevice);

Adc::connect<GpioInput26::In0, GpioInput27::In1, GpioInput28::In2, GpioInput29::In3>();
Adc::initialize();
Adc::enableTemperatureSensor();

while (true)
{
out.printf("---\r\n");
for (uint8_t ch = 0; ch < (uint8_t)Adc::Channel::Ch3; ++ch)
{
auto value = Adc::readChannel((Adc::Channel)ch);
out.printf("ADC Channel %u %f V | 0x%04x %u\r\n", ch, Adc::convertToVoltage(value),
value, value);
}
{
auto value = Adc::readChannel(Adc::Channel::Ch3);
out.printf("ADC VSYS %f V | 0x%04x %u\r\n", 3.f * Adc::convertToVoltage(value),
value, value);
}
{
auto value = Adc::readChannel(Adc::Channel::Temperature);
out.printf("ADC Int Temp %.4f C | 0x%04x %u\r\n", Adc::convertToTemperature(value),
value, value);
}
modm::delay(250ms);
Led::toggle();
}

return 0;
}
12 changes: 12 additions & 0 deletions examples/rp_pico/adc_simple/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:rp-pico</extends>
<options>
<option name="modm:build:build.path">../../../build/rp_pico/adc_simple</option>
</options>
<modules>
<module>modm:io</module>
<module>modm:platform:adc</module>
<module>modm:platform:uart:0</module>
<module>modm:build:scons</module>
</modules>
</library>
4 changes: 4 additions & 0 deletions src/modm/board/feather_rp2040/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct SystemClock
static constexpr uint32_t UsbPLLMul = 40;
static constexpr uint32_t RefFrequency = XOSCFrequency;
static constexpr uint32_t UsbFrequency = PllUsbFrequency;
static constexpr uint32_t AdcFrequency = PllUsbFrequency;
static constexpr uint32_t SysFrequency = Frequency;
static constexpr uint32_t PeriFrequency = SysFrequency;

Expand All @@ -59,6 +60,9 @@ struct SystemClock
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
ClockControl::configureClock<ClockControl::Clock::Usb, ClockControl::ClockSrc::PllUsb,
PllUsbFrequency, UsbFrequency>();
// CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
ClockControl::configureClock<ClockControl::Clock::Adc, ClockControl::ClockSrc::PllUsb,
PllUsbFrequency, AdcFrequency>();
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select
// and enable Normally choose clk_sys or clk_usb
ClockControl::configureClock<ClockControl::Clock::Peri, ClockControl::ClockSrc::Sys,
Expand Down
5 changes: 5 additions & 0 deletions src/modm/board/rp_pico/board.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
*
* Copyright (c) 2022, Andrey Kunitsyn
* Copyright (c) 2022, Nikolay Semenov
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -33,6 +34,7 @@ struct SystemClock
static constexpr uint32_t UsbPLLMul = 40;
static constexpr uint32_t RefFrequency = XOSCFrequency;
static constexpr uint32_t UsbFrequency = PllUsbFrequency;
static constexpr uint32_t AdcFrequency = PllUsbFrequency;
static constexpr uint32_t SysFrequency = Frequency;
static constexpr uint32_t PeriFrequency = SysFrequency;

Expand All @@ -56,6 +58,9 @@ struct SystemClock
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
ClockControl::configureClock<ClockControl::Clock::Usb, ClockControl::ClockSrc::PllUsb,
PllUsbFrequency, UsbFrequency>();
// CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
ClockControl::configureClock<ClockControl::Clock::Adc, ClockControl::ClockSrc::PllUsb,
PllUsbFrequency, AdcFrequency>();
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select
// and enable Normally choose clk_sys or clk_usb
ClockControl::configureClock<ClockControl::Clock::Peri, ClockControl::ClockSrc::Sys,
Expand Down
98 changes: 98 additions & 0 deletions src/modm/platform/adc/rp/adc.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2022, Nikolay Semenov
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include <modm/architecture/interface/adc.hpp>
#include <modm/platform/gpio/connector.hpp>

namespace modm::platform
{
/**
* Analog/Digital-Converter module.
*
* Not implemented yet:
* - Interrupts
* - FIFO
* - DMA
*
* \ingroup modm_platform_adc
*/
class Adc : public modm::Adc
{
public:
static constexpr uint8_t Resolution = 12;

public:
enum class Channel : uint8_t
{
%% for channel, name in channels.items() | sort
{{ name }} = {{ channel }},
%% endfor
};

public:
// start inherited documentation
template< class... Signals >
static void
connect()
{
using Connector = GpioConnector<Peripheral::Adc{{ id }}, Signals...>;
Connector::connect();
}

static inline void
initialize();

static inline void
disable();

static inline bool
setChannel(Channel);

static inline Channel
getChannel();

static inline bool
isReady();

static inline bool
hasError();

static inline uint16_t
getValue();

static inline uint16_t
readChannel(Channel);

static inline void
enableTemperatureSensor();

static inline void
disableTemperatureSensor();

static inline float
convertToVoltage(uint16_t value);

static inline float
convertToTemperature(uint16_t value);

private:
static inline void
reset();

static inline void
unreset();
};

} // namespace modm::platform

#include "adc_impl.hpp"
120 changes: 120 additions & 0 deletions src/modm/platform/adc/rp/adc_impl.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2022, Nikolay Semenov
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include <modm/platform/core/resets.hpp>

#include <hardware/structs/adc.h>

namespace modm::platform
{

void
Adc::initialize()
{
reset();
unreset();

adc_hw->cs = ADC_CS_EN_BITS;

while (!isReady()) { __NOP(); }
}

void
Adc::disable()
{
// TODO: wait for the current conversion to finish
adc_hw->cs = ADC_CS_EN_RESET;
}

bool
Adc::setChannel(Channel channel)
{
if (static_cast<uint32_t>(channel) > {{channels | max}}) return false;

hw_write_masked(&adc_hw->cs, static_cast<uint32_t>(channel) << ADC_CS_AINSEL_LSB, ADC_CS_AINSEL_BITS);
return true;
}

Adc::Channel
Adc::getChannel()
{
return static_cast<Adc::Channel>((adc_hw->cs & ADC_CS_AINSEL_BITS) >> ADC_CS_AINSEL_LSB);
}

bool
Adc::isReady()
{
return !!(adc_hw->cs & ADC_CS_READY_BITS);
}

bool
Adc::hasError()
{
return !!(adc_hw->cs & ADC_CS_ERR_BITS);
}

uint16_t
Adc::getValue()
{
// START_ONCE is ignored if START_MANY is set
// and isReady() will always return false.
hw_clear_bits(&adc_hw->cs, ADC_CS_START_MANY_BITS);
hw_set_bits(&adc_hw->cs, ADC_CS_START_ONCE_BITS);
while (!isReady()) { __NOP(); }
return static_cast<uint16_t>(adc_hw->result);
}

uint16_t
Adc::readChannel(Channel channel)
{
if (!setChannel(channel)) return 0;
return getValue();
}

void
Adc::enableTemperatureSensor()
{
hw_set_bits(&adc_hw->cs, ADC_CS_TS_EN_BITS);
}

void
Adc::disableTemperatureSensor()
{
hw_clear_bits(&adc_hw->cs, ADC_CS_TS_EN_BITS);
}

float
Adc::convertToVoltage(uint16_t value)
{
return value * (3.3f / (1 << 12));
}

float
Adc::convertToTemperature(uint16_t value)
{
return 27.f - (convertToVoltage(value) - 0.706f) / 0.001721f;
}

void
Adc::reset()
{
Resets::reset(RESETS_RESET_ADC_BITS);
}

void
Adc::unreset()
{
Resets::unresetWait(RESETS_RESET_ADC_BITS);
}

} // namespace modm::platform
Loading

0 comments on commit 6b9ef11

Please sign in to comment.