This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Help on ADC channels

Hi,
I use a MCBSTM32E evaluation board, which is composed of an STM32F103ZET6 MCU, and I loaded the measure example provided by Keil. It works perfectly, but I want to add another variable resistor on PC13 which is the channel 13 of ADC1. The onboard variable resistor is connected to channel 14.
Thus I configured the ADC to work with two channels (13 & 14), the DMA to have a buffersize of 2 and created an int ADC_ConvertedValue2 that should contain the second conversion result. I configured the channels like underneath : ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 2, ADC_SampleTime_55Cycles5);

My result is that each conversion result is store on the same variable (ADC_ConvertedValue) and the second one has nothing. I dont know how to get the value of the second conversion in the EOC interruption routine. Can I still use this interruption and do i have to use a DMA one ? I'm a bit confused about how ADC channels really works and neither the datasheet nor the FWLib helped me.
Thanks in advance for any hint.
Gary

Parents
  • Ok, thanks a lot. That is exactly what I wanted to know, how the DMA should proceed to store two values. But the point is that I found that on the example "Measure" from Keil doesnt use the IRQ. In fact for each instruction which concerns interruptions there are conditions if(n)def __USE_IRQ which permit to use it or not. I did not find where to put "__USE_IRQ" in order to activate interuptions...

Reply
  • Ok, thanks a lot. That is exactly what I wanted to know, how the DMA should proceed to store two values. But the point is that I found that on the example "Measure" from Keil doesnt use the IRQ. In fact for each instruction which concerns interruptions there are conditions if(n)def __USE_IRQ which permit to use it or not. I did not find where to put "__USE_IRQ" in order to activate interuptions...

Children
  • Interrupts and DMA are two separate mechanisms.

    You may use:
    - no interrupts, no DMA. Just poll the ADC.
    - no interrupts but DMA. Poll DMA or ADC when a full DMA transfer is done (all channels processed).
    - interrupts for each individual read, without use of DMA.
    - interrupts together with DMA - you get the interrupt when all enabled channels have been processed (and DMA have written the values into an array).

    If you are going to change existing code (or write new) then you must read the datasheet for the processor - especially the settings available for the DMA unit (if you decide to use DMA), the ADC and the interrupt logic (if you decide to use interrupts).

    In the end, there are almost always multiple ways to solve a problem. In your case, you must choose if you want to use interrupts or not and if you want to use DMA or not. If you do use DMA then you will have to configure it to step the destination address, since it isn't meaningful to use DMA for reading from ADC to memory unless you step the address. Either because you want multiple samples from one channel. Or you want one sample each from multiple channels. Without activating the destination step function, you would just overwrite the previous value. How you do it is described in the datasheet. If you want to use DMA is something you must decide.

    If you want to use interrupts, you may normally configure to get one interrupt for each ADC read, or one interrupt for each full pass through all activated ADC channels. How you do is mentioned in the datasheets. If you want to do it is something you must decide.

    If you want to poll the ADC to check if a value is ready (i.e. skip interrupts and DMA) the required information is in the datasheet. The decision to do this is up to you.

    If you want to use DMA and poll the DMA unit to check when a full DMA burst is done, then the datasheet should tell how to check the running state of the DMA unit. The decision if this is a good solution for your application is obviously up to you.

    What I would recommend is that you do your best to get it to work. Then post a reference to a named datasheet and tell what part of that text you don't understand. And/or a sample code that you have designed (based on information in examples and the datasheet) and what you think the code does, and what it actually does. Then people may comment about code lines where you might have misunderstood something, or where you might have forgotten required steps.

    About defining symbols to control your compilation (__USE_IRQ), you can open your target options and then select the tab "C/C++". The top text is "Preprocessor Symbols" and the first field is labeled "Define".

    If you write a symbol name there, you will directly see your compiler command line update in the bottom-most field of the tab.

    The tab "Asm" have similar fields for controlling symbols used together with assembler files.

  • Hello Gary Bisson,

    Set __USE_IRQ in uVision under options for target - C/C++ - Define.

    Best Regards,
    Martin Guenther

  • Thank you, both of you. Per Westermark, your explanations were clear thus I made a decision which is to first use only interrupts and read the Cortex datasheet. I tried the __USE_IRQ in the C/C++ define and it worked. I'll tell you when everything works.

  • I'm back on my problem. I made it work with DMA without interrupts. It works well, it is quite simple to get data in an array which size depends on the number of channels.
    I did not find how to generate an interrupt from DMA to tell that the transfer is done. I configured the DMA like this :

      /* DMA1 channel1 configuration */
      DMA_DeInit(DMA1_Channel1);
      DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
      DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_result;
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
      DMA_InitStructure.DMA_BufferSize = 2;
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
      DMA_InitStructure.DMA_Priority = DMA_Priority_High;
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
      DMA_Init(DMA1_Channel1, &DMA_InitStructure);
      /* Enable DMA1 channel1 */
      DMA_Cmd(DMA1_Channel1, ENABLE);
      DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1 , ENABLE);
    


    and the NVIC as below :

      NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
      NVIC_DeInit(); /*Deinitializes the NVIC*/
      NVIC_SCBDeInit();
      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQChannel;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    


    It seems to me that the problem comes from the NVIC because once it is initialised, my Systick_IRQHandler (which is necessary in my case to activate conversion every 10ms) runs only once and then doesnt work anymore.
    Do I need to put my systick interrupt in the NVIC structure ? I've seen that this latter is automatically in it. If I need to, what is the name of the IRQ_Channel because I tried SysTick but it did not compiled. Is it a better solution to use a timer to get my 10ms interrupt ?
    Thanks in advance (again).

    NB : Documents I read : Reference Manual (www.st.com/.../13902.pdf)
    Insider's Guide (www.st.com/.../1221142709.pdf)
    FWLib (www.st.com/.../13475.pdf)
    STM32 Datasheet (www.st.com/.../14611.pdf)

  • I come back to say that my problem is solved. It was a mistake which came from a bad example. In fact, I had put DMA1_Channel1_IRQHandler() as the prototype. It did not generate any error during compilation, but the true one is DAMChannel1_IRQHandler(). Now the DMA works perfectly.
    But I have a new problem which is more hardware in fact. I "cannot acces memory" when trying to load my program. I think I know why it doesnt work anymore (probably because I used the pins A which are the JTAG one). How can I reset the whole thing ?

  • Hello Gery Bisson,

    I am not shure if this will help but you can try to use Serial Wire Debug port instead of JATG.

    If you are using a ULINK2/ULINK-ME than change the settings in uVision for Ulink Cortex Debugger. In Cortex-M Target Driver Setup check SWJ and set port to SW. If this works you will see under SW Device a IDCode.
    Please see also www.keil.com/.../ulink2_ctx_jtag_adapter.htm.

    Best Regards,
    Martin Guenther

  • Thank you. I did not know what was the SWJ, now I do. But I encountered the same problem. I think it is each time the Cortex is in sleep mode (I cannot access memory). I tried my infinite loop without the __WFI() instruction and now I can load my programs easily.

  • Several processors will drop the JTAG support when sleeping. The sleep turns off clocking to too large sections of the processor, making it inert until it receives an interrupt.