Basics-Wrapup

View on GitHub

Analog-to-Digital Converter

this peripheral is a very simple one it depends on sampling an analog value and converting this voltage value to a digital code using encoder which converts this signal to a digital code

also according to niquist theorem : Fs>=2Fmax

which states that sampling frequency must be at least twice the frequency of the signal

also if sampling frequency is lower than the signal frequency the aliasing occurs causing the sampling to be corrupted

Quantisation means trying to quantify or make some approximation to the continuous signal to move it to a digital domain in order to read its value

ADC Circuit Diagram

using k-map you can design the priority encoder :D

some characteristics in our stm32

PA0 -> ADC12_IN0
PA1 -> ADC12_IN1
PA2 -> ADC12_IN2
PA3 -> ADC12_IN3
PA4 -> ADC12_IN4
PA5 -> ADC12_IN5
PA6 -> ADC12_IN6
PA7 -> ADC12_IN7
PB0 -> ADC12_IN8
PB1 -> ADC12_IN9

PC0 -> ADC12_IN10
PC1 -> ADC12_IN11
PC2 -> ADC12_IN12
PC3 -> ADC12_IN13
PC4 -> ADC12_IN14
PC5 -> ADC12_IN15

ADC12_IN16 -> (connected internally to the temperature sensor)

operational functions

operation with interrupts

we can use interrupts but we need to define a flag for that operation to indicate the peripheral fired the interrupt by setting the flag of the module firing an interrupt

following these steps to define an interrupt with watchdog interrupt firing events for low and high thresholds interrupt events

    //which adc we will use ? adc1
    int adc1_int = 0;
    int adc2_int = 0;
    //data container argument
    int analog_rx = 0;
    //flag indicating data interrupt occured and analog_rx is loaded with data
    char adc1_flag = 0;
    char adc2_flag = 0;

    int adc1_wd = 1;
    int adc2_wd = 0;

operation with multi-channel

challenges :

generally we have two ways to solve this problem

the only way is reading channel by channel with two ways

  1. scan mode -> scanning the 17th channels using the sequence register ADC_SQRx(x = 1..3)

  2. Discontinuous mode -> scanning limited number of channels using the seq register ADC_SQRx (x=1..3)

both of them are using DMA peripheral to make the manupulation but for now we are not gona use this configuration

    void ADC_multi_channel_init(int adc,int channels, int * adc_channels){
        int i=0;

        for(i=0;i< channels;i++){
            if(adc_channels[i] < 8){
                init_GP(PA, adc_channels[i], IN, I_AN);
            }
            else if(adc_channels[i] < 10){
                init_GP(PB, adc_channels[i]-8, IN, I_AN);
            }
            else if(adc_channels[i] < 16){
                init_GP(PC, adc_channels[i]-10, IN, I_AN);
            }
        }

        volatile int ADC_RCC_APB2ENR[] = {0x201,0x401};

        ADC_TypeDef * ADCs[] = {ADC1,ADC2};
        //setup the clock for the ADC peripheral
        RCC->APB2ENR |= ADC_RCC_APB2ENR[adc-1];

        ADCs[adc-1]->CR2 = 0;//ADC off and reset all bits
        ADCs[adc-1]->CR2 |= 1;//ADC on
        __asm__("nop \n"
                "nop \n");
        ADCs[adc-1]->SQR3 = adc_channels[i];

        ADCs[adc-1]->CR2 |= 2;//continuous reading
        ADCs[adc-1]->CR2 |= 1;//starting the conversion
    }
    void ADC_Multi_channel_rx(int adc, int channels, int *adc_channels, int *analog_rx){
        ADC_TypeDef * ADCs[] = {ADC1,ADC2};
        int temp_rx = 0;
        int i = 0;

        while(1){
            if(adc_check(adc)){
                temp_rx = ADCs[adc-1]->DR;
                analog_rx[i] = (temp_rx);
                i++;
                if(i == channels){
                    i =0;
                    ADCs[adc-1]->SQR3 = adc_channels[i];
                    break;
                }
                else
                    ADCs[adc-1]->SQR3 = adc_channels[i];
            }
        }
    }