Skip to content
Snippets Groups Projects

[internal-adc] Internal ADC driver rewrite

Merged Alberto Nidasio requested to merge adc-dev into sensors-dev
2 files
+ 373
0
Compare changes
  • Side-by-side
  • Inline
Files
2
/* Copyright (c) 2020 Skyward Experimental Rocketry
* Authors: Alberto Nidasio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "InternalADC.h"
InternalADC::InternalADC(ADC_TypeDef& ADCx_) : ADCx(ADCx_)
{
resetConfiguration();
}
InternalADC::~InternalADC() { resetConfiguration(); }
bool InternalADC::init()
{
// 1: Turn on the ADC
ADCx.CR2 |= ADC_CR2_ADON;
// 2: Set single conversion mode
ADCx.CR2 &= ~ADC_CR2_CONT;
// 5: Set scan mode
ADCx.CR1 |= ADC_CR1_SCAN;
// 6: Data alignment
ADCx.CR2 &= ~ADC_CR2_ALIGN; // right
return true;
}
void InternalADC::enableChannel(Channel channel)
{
enableChannel(channel, CYCLES_3);
}
void InternalADC::enableChannel(Channel channel, SampleTime sampleTime)
{
// Add channel to the sequence
if (!isUsingDMA)
{
addInjectedChannel(channel);
}
else
{
addRegularChannel(channel);
}
// Set channel's sample time
setChannelSampleTime(channel, sampleTime);
}
float InternalADC::getVoltage(Channel channel)
{
if (!isUsingDMA)
{
return readVoltage(channel);
}
else
{
// TODO
return 0;
}
}
bool InternalADC::selfTest() { return true; }
ADCData InternalADC::sampleImpl()
{
if (!isUsingDMA)
{
startInjectedConversion();
// Wait for end of conversion
while (!(ADCx.SR & ADC_SR_JEOC))
;
}
else
{
// TODO
}
return last_sample;
}
inline void InternalADC::resetConfiguration()
{
// Reset the ADC configuration
ADCx.CR1 = 0;
ADCx.CR2 = 0;
ADCx.SMPR1 = 0;
ADCx.SMPR2 = 0;
ADCx.JOFR1 = 0;
ADCx.JOFR2 = 0;
ADCx.JOFR3 = 0;
ADCx.JOFR4 = 0;
ADCx.HTR = 0;
ADCx.LTR = 0;
ADCx.SQR1 = 0;
ADCx.SQR2 = 0;
ADCx.SQR3 = 0;
ADCx.JSQR = 0;
}
inline void InternalADC::startRegularConversion()
{
ADCx.CR2 |= ADC_CR2_SWSTART;
}
inline void InternalADC::startInjectedConversion()
{
ADCx.CR2 |= ADC_CR2_JSWSTART;
}
inline bool InternalADC::addRegularChannel(Channel channel)
{
// Check active channels number
if (activeChannels >= 16)
{
return false;
}
// Add the channel to the sequence
volatile uint32_t* sqrPtr;
switch (activeChannels % 6)
{
case 1:
sqrPtr = &(ADCx.SQR3);
case 2:
sqrPtr = &(ADCx.SQR2);
default:
sqrPtr = &(ADCx.SQR1);
}
*sqrPtr = channel << ((activeChannels / 6) * 5);
// Update the channels number in the register and update the counter
ADCx.SQR1 |= activeChannels << 20;
activeChannels++;
return true;
}
inline bool InternalADC::addInjectedChannel(Channel channel)
{
// Check active channels number
if (activeChannels >= 4)
{
return false;
}
// Add the channel to the sequence
ADCx.JSQR |= channel << (activeChannels * 5);
// Update the channels number in the register and update the counter
ADCx.JSQR |= activeChannels << 20;
activeChannels++;
return true;
}
inline void InternalADC::setChannelSampleTime(Channel channel,
SampleTime sampleTime)
{
volatile uint32_t* smprPtr;
if (channel <= 9)
{
smprPtr = &(ADCx.SMPR2);
}
else
{
smprPtr = &(ADCx.SMPR1);
}
*smprPtr = sampleTime << (channel * 3);
}
inline float InternalADC::readVoltage(Channel channel)
{
float voltage;
if (!isUsingDMA)
{
voltage = readInjectedChannel(channel);
voltage *= V_SUPPLY;
voltage /= RESOLUTION;
}
else
{
// TODO
voltage = 0;
}
return voltage;
}
inline uint16_t InternalADC::readInjectedChannel(Channel channel)
{
volatile uint32_t* jdrPtr;
// Check which of the injected channels we need to get
if ((ADCx.JSQR & ADC_JSQR_JSQ1) == channel && activeChannels >= 1)
{
jdrPtr = &(ADCx.JDR1);
}
else if ((ADCx.JSQR & ADC_JSQR_JSQ2) == channel && activeChannels >= 2)
{
jdrPtr = &(ADCx.JDR2);
}
else if ((ADCx.JSQR & ADC_JSQR_JSQ3) == channel && activeChannels >= 3)
{
jdrPtr = &(ADCx.JDR3);
}
else if ((ADCx.JSQR & ADC_JSQR_JSQ4) == channel && activeChannels >= 4)
{
jdrPtr = &(ADCx.JDR4);
}
else
{
return 0;
}
return *jdrPtr;
}
\ No newline at end of file
Loading