YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
adc_rp2040.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14#include "RP2040.h"
15#include "adc_rp2040.h"
16#include "task.h"
17#include <cassert>
18
19using namespace _IO_BANK0_;
20
21adc_rp2040 adc_rp2040::inst;
22
23adc_rp2040::adc_rp2040() {
24 // Enable the ADC
25 _ADC_::ADC.CS.EN = 1;
26 while (!_ADC_::ADC.CS.READY) ;
27 // Prepare ADC inputs
28 for (int i=26; i <= 29; ++i) {
29 // Disable pull-resistors
30 _PADS_BANK0_::PADS_BANK0.GPIO[i].PUE = 0;
31 _PADS_BANK0_::PADS_BANK0.GPIO[i].PDE = 0;
32 }
33}
34
35void adc_rp2040::adcMode(uint8_t channel, uint16_t mode) {
36 assert(channel < 8);
37 assert(mode < ADC::ADC_14_BIT);
38 _modes[channel] = mode;
39}
40
41adc_mode_t adc_rp2040::getMode(uint8_t channel) {
42 assert(channel < 8);
43 return _modes[channel];
44}
45
46uint16_t adc_rp2040::adcReadRaw(uint8_t channel) {
47 assert(channel < 8);
48 // Enter a critical section for setting GPIO18 and
49 // reading the ADC value.
50 task::enterCritical();
51 // Set GPIO18 according to the ADC channel
52 IO_BANK0_SET.GPIO18_CTRL.OEOVER <<= GPIO_CTRL_OEOVER__ENABLE;
53 if (channel & 1) {
54 IO_BANK0.GPIO18_CTRL.OUTOVER = GPIO_CTRL_OUTOVER__HIGH;
55 } else {
56 IO_BANK0.GPIO18_CTRL.OUTOVER = GPIO_CTRL_OUTOVER__LOW;
57 }
58 // Read the 12 bit ADC result
59 _ADC_::ADC.CS.AINSEL = (channel / 2);
60 _ADC_::ADC.CS.START_ONCE = 1;
61 while(!_ADC_::ADC.CS.READY) ;
62 uint16_t result = _ADC_::ADC.RESULT;
63 // Leave the critical section
64 task::leaveCritical();
65 // Release GPIO18
66 IO_BANK0_CLR.GPIO18_CTRL.OEOVER <<= GPIO_CTRL_OEOVER__ENABLE;
67 IO_BANK0_CLR.GPIO18_CTRL.OUTOVER <<= GPIO_CTRL_OUTOVER__HIGH;
68 // Our ADC has no real 8 or 10 bit modes, so we simulate
69 // the behaviour by shifting the result...
70 switch(_modes[channel]) {
71 case ADC::ADC_8_BIT:
72 return result >> 4;
73 case ADC::ADC_10_BIT:
74 return result >> 2;
75 default:
76 case ADC::ADC_12_BIT:
77 return result;
78 }
79}
80
81float adc_rp2040::adcReadVoltage(uint8_t channel) {
82 return rawToVoltage(channel, adcReadRaw(channel));
83}
84
85float adc_rp2040::rawToVoltage(uint8_t channel, uint16_t raw) {
86 float voltage = 3.3f * (float)raw;
87 switch(_modes[channel]) {
88 case ADC::ADC_8_BIT:
89 voltage /= 255.0f;
90 break;
91 case ADC::ADC_10_BIT:
92 voltage /= 1023.0f;
93 break;
94 default:
95 case ADC::ADC_12_BIT:
96 voltage /= 4095.0f;
97 break;
98 }
99 return voltage;
100}
CMSIS-Core(M) Device Peripheral Access Layer Header File for Device RP2040.