cancel
Showing results for 
Search instead for 
Did you mean: 

Something wrong in program using STM32F103 ADC.

WOGoos
Associate II

Dear reader

I hope someone can help me with my question. I have programmed an ADC1 on a STM32F103 with the following functions activated:

  • Continues conversion mode
  • Scan mode with two channels A0 And A1
  • DMA to an array in memory ADC_data[2]
  • ( ADC Interrupt enabled which is the problem)

It all works and generates output based on the code below. The output generated in the loop looks like this

ADC1 = 2890 
ADC2 = 0 
ADCcnt = 0 
ADC_data[0] = 2906 
ADC_data[1] = 0 

But when I add and activate the interrupt function using NVIC_EnableIRQ which basically only counts the nr of conversions I have a problem.

When I comment in line 89 NVIC_EnableIRQ(ADC1_2_IRQn); everything work till the end of the setup functions but as soon line 89 is executed the loop stops and everything hangs.

I checked the code against what others do but I can't find what is wrong.

What am i missing that i do wrong.

uint16_t          value;
uint32_t          val32, ADCcnt=0;
uint16_t          ADC_data[2] = { 0xAAAA, 0x5555 };
/*
    HEX_MEM	: Function to output a given section of memory starting from ptr till ptr+(rowa x cols)
              a integers mutiple of cols is always output.
    cols	: nr of colums to out put
    rows	: nr of rows to be displayed
    ptr		: pointer/address to the data area to be examend.
    Note    : replace the prinf() funccvtion
*/
void HEX_MEM(void* ptr, uint8_t width, uint8_t c, uint8_t r) {
 
    uint8_t	cols = c, rows = r;
    uint8_t rcnt, ccnt;
    uint8_t* ptr8;
 
    ptr8 = (uint8_t*)ptr;
 
    switch (width) {
        case 8: {
            Serial.printf("HEX-MEM    ");
            for (ccnt = 0; ccnt < cols; ccnt++) Serial.printf("  %X", ccnt);
            Serial.printf("\r\n");
 
            for (rcnt = 1; rcnt <= rows; rcnt++) {
                Serial.printf("%p: ", ptr8);
                for (ccnt = 1; ccnt <= cols; ccnt++) {
                    Serial.printf("%02X ", (*ptr8));
                    ptr8++;
                }
                ptr8 -= ccnt - 1;
                for (ccnt = 1; ccnt <= cols; ccnt++) {
                    if (*ptr8 >= 0x20 && *ptr8 <= 0x7E) Serial.printf("%c.", *ptr8);
                    else Serial.printf("-.");
                    ptr8++;
                }
                Serial.printf("\r\n");
            }
        } break;
        default: Serial.println("Error");
    }
}
 
void ADC1_IRQHandler(void) {                      // ADC Interupt ISR
    ADC1->SR &= ~(0x00000002);                    // clear EOC status bit
    val32 = ADC1->DR;
    ADCcnt++;
}
 
void setup()                                       // The setup() function runs once each time the micro-controller starts
{
    Serial.begin(115200);
    delay(2000);
    Serial.println("program start");
 
    Serial.println("RCC1 ==========================");
    HEX_MEM((uint8_t*)RCC, 8, 4, 9);
     
    RCC->APB2ENR  = 0x00004615;                   // Enable: UART1 ADC1, ADC2, IOPCEN IOPAEN, AFIOEN  
    RCC->AHBENR   = 0x00000015;                   // enable: SRAM, Flash, DMA
    GPIOC->CRH    = 0x44144444;                   // Enable: port C PC13 as digital output
    GPIOA->CRL    = 0x44444400;                   // Enable: port A PA0 PA1 as analog input
 
    ADC1->SMPR2   = 0x0000003F;                   // Set Sample time chanel A0 A1 to 239.5 cycles
    ADC1->SQR3    = 0x00000020;                   // Set scan sequence[1.2] to cahnnel A0 en A1  
    ADC1->SQR1    = 0x00100000;                   // Set scan sequence cnt=2 cycles 
    ADC1->CR1     = 0x00000120;                   // Enable: Scan Mode, IRQ enabled
    ADC1->CR2     = 0x00000107;                   // Enable: DMA, Calibrate, Continues sample Mode, Wakup the ADC
 
    DMA1_Channel1->CNDTR  =  0x00000002;          // DMA cycle cnt=2
    DMA1_Channel1->CPAR   = (uint32_t)&ADC1->DR;  // DMA periferal register adress = ADC.DR
    DMA1_Channel1->CMAR   = (uint32_t)ADC_data;   // DMA Memeory adress = ADC_data[0]
    DMA1_Channel1->CCR    = 0x000005A0;           // Set: MEM=16b, PER=16b, MINC=1, CIR=1, EN=1
    DMA1_Channel1->CCR |= 0x00000001;             // Enable DMA channel1
    delay(1);                                     // Stabelise ADCmachine and calibration process(5uS).
    ADC1->CR2          |= 0x00000001;             // Enable: ADC ADC sampling machine
 
    Serial.println("RCC2 ===========================");          // Print out memeory/register section
    HEX_MEM((uint8_t*)RCC, 8, 4, 9);
    Serial.println("GPIOA ==========================");          // Print out memeory/register section
    HEX_MEM((uint8_t*)GPIOA, 8, 4, 7);
    Serial.println("GPIOC ==========================");          // Print out memeory/register section
    HEX_MEM((uint8_t*)GPIOC, 8, 4, 7);
    Serial.println("ADC1 ===========================");          // Print out memeory/register section
    HEX_MEM((uint8_t*)ADC1, 8, 4, 20);
    delay(5000);                                                 // Just wait 5 seconds
    NVIC_SetPriority(ADC1_2_IRQn, 5);              // Set the ADC interupt priority
//    NVIC_EnableIRQ(ADC1_2_IRQn);                   // Enable the ADC interupt.
}
 
 
void loop()                                        // Add the main program code into the continuous loop() function
{
    digitalWrite(PC13, !digitalRead(PC13));        // Turn the LED from off to on, or on to off
    delay(1000);
 
    Serial.printf("ADC1 = %i \n", ADC1->DR & 0x0000FFFF);
    Serial.printf("ADC2 = %i \n", ADC1->DR >>16);
    Serial.printf("ADCcnt = %i \n", ADCcnt);
    Serial.printf("ADC_data[0] = %i \n", ADC_data[0] & 0xFFFF);
    Serial.printf("ADC_data[1] = %i \n", ADC_data[1] & 0xFFFF);
    Serial.println();
}

4 REPLIES 4

> NVIC_EnableIRQ(ADC1_2_IRQn)

The name of the ISR suspiciously doesn't match the symbol you use as parameter here, so check in the startup code/vector table the proper ISR name.

Also, you use C++ rather than C, isn't name mangling involved? Ultimately, check in disasm that the proper address is inserted in the vector table.

> ADC1->SR &= ~(0x00000002); // clear EOC status bit

Also this probably doesn't cause directly your problem, but don't RMW into the status register, write directly.

JW

Hi Jan, Thanks for trying to help me. I'm working with the IDE of Ardiono but write my software in Visual studio. For the IDE the name of the ISR functions is predefined and loaded in the NVIC interrupt table during compile time. To enable the interrupts in the NVIC the IRQ number must be specified with is defined as ADC1_2_IRQn and has value 18. ISR name and IRQn are not equal but are related.

TDK
Guru

If you set a breakpoint at line 46, does it get hit? I'm not convinced ADC1_IRQHandler is defined correctly.

If you feel a post has answered your question, please click "Accept as Solution".
WOGoos
Associate II

Hi TDK,

I can't set breakpoints, but I can tell you this When I exclude line #86 it works, when i include line 86 it hangs.

I figured out that the interrupt vector table can't be changed the function names for the handles are predefined like ADC1_IRQHandler. I did a check on the address of this function against the address what was in the interrupt vector table and the addresses were different. It seems that by default the Interrupt vector is either a NULL functions or a While(1) forever function. I see my software hanging as soon it call the interrupt functions. It looks like i address a While(1) for ever functions.

It looks like I have a problem with matching the function addresses.

I did dry to use the  NVIC_SetVector(TIM4_IRQn, (uint32_t)TIM4_IRQHandler); but now for a TIM4 interrupt, no effect the addresses stay different. I also checked if MS studio refers to the declaration of this ADC1_IRQHandler declaration and it doesn't it sees it as new declared function and that explains the difference in addresses.

My conclusion

I program based on a arduino IDE and use MS studio as a editor. Arduino IDE knows how to attachInterrupts() to a GPIO port but there is no interface for other periferals like TIM and ADC's. The predefined handler function like ADC1_IRQHandler being part of the HAL liberies are not supported under the Arduino IDE environment. Parts of the Hall library are implemented but other parts are missing. My use ISR calls ADC1_IRQHandler and TIM4_IRQHandler are considderd new functionnames and don't mats with the vectors in the fixed ISR vector table.

Question how do I solve that ?