AnsweredAssumed Answered

Setup for SDADC three channel synchronization with SDADC1 example

Question asked by VladUA on Mar 21, 2015
hi there,

because I could not find any example of successful simultaneous three-way conversion settings for SDADS, had to spend half a day time :)

Maybe someone it will be useful as well.

The program does not use DMA and hard bindings conversion to timers, it can be added later. Here is a simple example SDADC working on STM32F373 with
STM32F37x Standard Peripherals Library Drivers V1.0.0 /20-September-2012.


001./*
002. 
003.  FILE:     adc3d.c
004.  MODULE:   SDADC interface three channel syncro
005.  TARGET:   STM32F373
006.  Start at  18.03.2015 13:36
007. 
008.  Written by Vlad Zaritsky. 2015
009. 
010.*/
011. 
012.#include "header.h"
013. 
014.#define ADC3D_ST_OFF    50
015.#define ADC3D_ST_READY  55
016. 
017.#define ADC3D_RAW_LEN   128
018. 
019.// variables --------------------------------------------------------
020. 
021.__no_init uint8_t adc3d_state;
022.__no_init uint32_t adc3d_timer;
023. 
024.__no_init uint16_t adc3d_adc_index;
025. 
026.__no_init int16_t adc3d_raw_x[ ADC3D_RAW_LEN ];
027.__no_init int16_t adc3d_raw_y[ ADC3D_RAW_LEN ];
028.__no_init int16_t adc3d_raw_z[ ADC3D_RAW_LEN ];
029. 
030.// init procedure ---------------------------------------------------
031. 
032.void adc3d_init( void )
033.{
034. SDADC_InitTypeDef sdadcini;
035. SDADC_AINStructTypeDef analogini;
036. GPIO_InitTypeDef gpioini;
037. 
038.// SDADC step by step initialization as desribed in :
039.// STM32F37x Standard Peripherals Library Drivers
040. 
041.//  * @file    stm32f37x_sdadc.c
042.//  * @author  MCD Application Team
043.//  * @version V1.0.0
044.//  * @date    20-September-2012
045. 
046.// See section ##### How to use this driver #####
047. 
048.//    (1) Enable the SDADC analog interface by calling
049.//        PWR_SDADCAnalogCmd(PWR_SDADCAnalog_x, Enable);
050. 
051. RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR, ENABLE );
052. 
053. PWR_SDADCAnalogCmd( PWR_SDADCAnalog_1, ENABLE );
054. PWR_SDADCAnalogCmd( PWR_SDADCAnalog_2, ENABLE );
055. PWR_SDADCAnalogCmd( PWR_SDADCAnalog_3, ENABLE );
056. 
057.//    (2) Enable the SDADC APB clock to get write access to SDADC registers using
058.//        RCC_APB1PeriphClockCmd() function
059.//        e.g.  To enable access to SDADC1 registers use
060.//        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SDADC1, ENABLE); * really? do not trust them. the SDADCx use APB2 *
061. 
062. RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR, ENABLE );
063. RCC_APB2PeriphClockCmd( RCC_APB2Periph_SDADC1 | RCC_APB2Periph_SDADC2 |
064.                         RCC_APB2Periph_SDADC3, ENABLE );
065. 
066.// SDADC_Cmd( SDADC1, DISABLE );
067.// SDADC_Cmd( SDADC2, DISABLE );
068.// SDADC_Cmd( SDADC3, DISABLE );
069. 
070.//    (3) The SDADCs are clocked by APB1.
071.//        In order to get the SDADC running at the typical frequency (6 MHz
072.//        in fast mode), use SDADC prescaler by calling RCC_SDADCCLKConfig() function
073.//        e.g. if APB1 is clocked at 72MHz, to get the SDADC running at 6MHz
074.//        configure the SDADC prescaler at 12 by calling
075.//        RCC_SDADCCLKConfig(RCC_SDADCCLK_SYSCLK_Div12);
076. 
077.// RCC_SDADCCLKConfig( RCC_SDADCCLK_SYSCLK_Div48 );   //1.5MHz @ 72MHz
078. 
079. // Set the SDADC divider: The SDADC should run @6MHz
080. RCC_SDADCCLKConfig( RCC_SDADCCLK_SYSCLK_Div12 );
081. 
082. //GPIO pin preset
083. GPIO_StructInit( &gpioini );
084. RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOE, ENABLE );
085. 
086. gpioini.GPIO_Mode = GPIO_Mode_AN;
087. gpioini.GPIO_PuPd = GPIO_PuPd_NOPULL;
088. gpioini.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_15;
089. GPIO_Init( GPIOB, &gpioini );
090. 
091. gpioini.GPIO_Pin = GPIO_Pin_8;
092. GPIO_Init( GPIOE, &gpioini );
093. 
094.//    (4) If required, perform the following configurations:
095.//        (4.1) Select the reference voltage using SDADC_VREFSelect() function
096. 
097.// SDADC_VREFSelect( SDADC_VREF_VDDA );    // Select VDDA as reference
098.// SDADC_VREFSelect( SDADC_VREF_Ext );
099. 
100.//        (4.2) Enable the power-down and standby modes using SDADC_PowerDownCmd()
101.//             and SDADC_StandbyCmd() functions respectively
102.//        (4.3) Enable the slow clock mode (SDADC running at 1.5 MHz) using
103.//             RCC_SDADCCLKConfig() and SDADC_SlowClockCmd() function
104.//             -@@- These configurations are allowed only when the SDADC is disabled.
105. 
106. //ADC slow @ 1.5MHz
107.// SDADC_SlowClockCmd( SDADC1, ENABLE );
108.// SDADC_SlowClockCmd( SDADC2, ENABLE );
109.// SDADC_SlowClockCmd( SDADC3, ENABLE );
110. 
111.//    (5) Enable the SDADC peripheral using SDADC_Cmd() function.
112. 
113. SDADC_Cmd( SDADC1, ENABLE );
114. SDADC_Cmd( SDADC2, ENABLE );
115. SDADC_Cmd( SDADC3, ENABLE );
116. 
117. while( SDADC_GetFlagStatus( SDADC1, SDADC_FLAG_STABIP ) == SET );
118. while( SDADC_GetFlagStatus( SDADC2, SDADC_FLAG_STABIP ) == SET );
119. while( SDADC_GetFlagStatus( SDADC3, SDADC_FLAG_STABIP ) == SET );
120. 
121. //wait 5ms
122. adc3d_timer = 320000L;
123. while(adc3d_timer > 0L) { asm("nop"); adc3d_timer--; }
124. 
125.//    (6) Enter initialization mode using SDADC_InitModeCmd() function
126.//        then wait for INITRDY flag to be set to confirm that the SDADC
127.//        is in initialization mode.
128. 
129. // Initialization begins
130. SDADC_InitModeCmd( SDADC1, ENABLE );
131. SDADC_InitModeCmd( SDADC2, ENABLE );
132. SDADC_InitModeCmd( SDADC3, ENABLE );
133. 
134. while( SDADC_GetFlagStatus( SDADC1, SDADC_FLAG_INITRDY ) == RESET );
135. while( SDADC_GetFlagStatus( SDADC2, SDADC_FLAG_INITRDY ) == RESET );
136. while( SDADC_GetFlagStatus( SDADC3, SDADC_FLAG_INITRDY ) == RESET );
137. 
138.//    (7) Configure the analog inputs: gain, single ended mode, offset value and
139.//        commmon mode using SDADC_AINInit().
140.//        There are three possible configuration: SDADC_Conf_0, SDADC_Conf_1 and SDADC_Conf_2
141. 
142. //Preset SDADC_Conf_x profile
143. SDADC_AINStructInit( &analogini );
144. analogini.SDADC_CommonMode = SDADC_CommonMode_VSSA;
145. analogini.SDADC_Gain = SDADC_Gain_1;
146. analogini.SDADC_Offset = 0;
147. analogini.SDADC_InputMode = SDADC_InputMode_SEZeroReference;
148. 
149. // Configuration
150. SDADC_AINInit( SDADC1, SDADC_Conf_0, &analogini );
151. SDADC_AINInit( SDADC2, SDADC_Conf_1, &analogini );
152. SDADC_AINInit( SDADC3, SDADC_Conf_2, &analogini );
153. 
154.//    (8) Associate the selected configuration to the channel using SDADC_ChannelConfig()
155. 
156. SDADC_ChannelConfig( SDADC1, SDADC_Channel_4, SDADC_Conf_0 );  //SDADC1.4 x
157. SDADC_ChannelConfig( SDADC2, SDADC_Channel_8, SDADC_Conf_1 );  //SDADC2.8 y
158. SDADC_ChannelConfig( SDADC3, SDADC_Channel_7, SDADC_Conf_2 );  //SDADC3.7 z
159. 
160.//    (9) For Regular channels group configuration
161.//        (9.1) use SDADC_Init() function to select the SDADC channel to be used
162.//             for regular conversion, the continuous mode...
163.//             -@@- Only software trigger or synchro with SDADC1 are possible
164.//                  for regular conversion
165. 
166. sdadcini.SDADC_Channel = SDADC_Channel_4 ;
167. sdadcini.SDADC_ContinuousConvMode = ENABLE;
168. sdadcini.SDADC_FastConversionMode = DISABLE;
169. SDADC_Init( SDADC1, &sdadcini );
170. 
171. sdadcini.SDADC_Channel = SDADC_Channel_8 ;
172. SDADC_Init( SDADC2, &sdadcini );
173. 
174. sdadcini.SDADC_Channel = SDADC_Channel_7 ;
175. SDADC_Init( SDADC3, &sdadcini );
176. 
177. SDADC_RegularSynchroSDADC1( SDADC2, ENABLE );
178. SDADC_RegularSynchroSDADC1( SDADC3, ENABLE );
179. 
180. // Injected conversion synchronously with SDADC1 (not used here)
181.// SDADC_InjectedSynchroSDADC1( SDADC2, ENABLE );
182.// SDADC_InjectedSynchroSDADC1( SDADC3, ENABLE );
183. 
184.//    (10) For Injected channels group configuration
185.//        (10.1) Select the SDADC channel to be used for injected conversion
186.//             using SDADC_InjectedChannelSelect()
187. 
188.// Injected cahnnels not used here
189.// SDADC_InjectedChannelSelect( SDADC1, SDADC_Channel_4 );        //SDADC1.4 x
190.// SDADC_InjectedChannelSelect( SDADC2, SDADC_Channel_8 );        //SDADC2.8 y
191.// SDADC_InjectedChannelSelect( SDADC3, SDADC_Channel_7 );        //SDADC3.7 z
192. 
193.//    (11)  Exit initialization mode using SDADC_InitModeCmd() function
194. 
195. // Initialization ends
196. SDADC_InitModeCmd( SDADC1, DISABLE );
197. SDADC_InitModeCmd( SDADC2, DISABLE );
198. SDADC_InitModeCmd( SDADC3, DISABLE );
199. 
200. while( SDADC_GetFlagStatus( SDADC1, SDADC_FLAG_INITRDY ) == SET );
201. while( SDADC_GetFlagStatus( SDADC2, SDADC_FLAG_INITRDY ) == SET );
202. while( SDADC_GetFlagStatus( SDADC3, SDADC_FLAG_INITRDY ) == SET );
203. 
204. //Calibration
205. SDADC_CalibrationSequenceConfig( SDADC1, SDADC_CalibrationSequence_1 );
206. SDADC_StartCalibration( SDADC1 );
207. while( SDADC_GetFlagStatus( SDADC1, SDADC_FLAG_EOCAL ) == RESET );
208. 
209. SDADC_CalibrationSequenceConfig( SDADC2, SDADC_CalibrationSequence_1 );
210. SDADC_StartCalibration( SDADC2 );
211. while( SDADC_GetFlagStatus( SDADC2, SDADC_FLAG_EOCAL ) == RESET );
212. 
213. SDADC_CalibrationSequenceConfig( SDADC3, SDADC_CalibrationSequence_1 );
214. SDADC_StartCalibration( SDADC3 );
215. while( SDADC_GetFlagStatus( SDADC3, SDADC_FLAG_EOCAL ) == RESET );
216. 
217. adc3d_adc_index = 0;
218. adc3d_state = ADC3D_ST_READY;
219. adc3d_timer = 0L;
220.}
221. 
222.// timer event or direct main loop call -----------------------------
223. 
224.void adc3d_timer_event( void )
225.{
226. adc3d_timer++;
227. if( adc3d_timer > 30000L )
228.  {
229.   #ifdef __debug__
230.   USART1_puts( "\r\n.SDADC TIMEOUT" );
231.   #endif
232. 
233.   adc3d_timer = 0L;
234.   adc3d_adc_start();
235.  }
236. //is conversion end?
237. else if( SDADC_GetFlagStatus( SDADC1, SDADC_FLAG_REOC ) &&
238.          SDADC_GetFlagStatus( SDADC2, SDADC_FLAG_REOC ) &&
239.          SDADC_GetFlagStatus( SDADC3, SDADC_FLAG_REOC ) )
240.  {
241.   adc3d_raw_x[ adc3d_adc_index ] = SDADC_GetConversionValue( SDADC1 );
242.   adc3d_raw_y[ adc3d_adc_index ] = SDADC_GetConversionValue( SDADC2 );
243.   adc3d_raw_z[ adc3d_adc_index ] = SDADC_GetConversionValue( SDADC3 );
244. 
245.   adc3d_adc_index++;
246. 
247.   //loop when array is full
248.   if( adc3d_adc_index >= ADC3D_RAW_LEN )
249.    {
250.     adc3d_adc_index = 0;
251.     adc3d_adc_process();
252.    }
253. 
254.   //to restart conversion
255.   adc3d_timer = 0L;
256.   adc3d_adc_start();
257.  }
258.}
259. 
260.// Start the three channel synchronous conversion
261. 
262.void adc3d_adc_start( void )
263.{
264. // Launches injected conversion synchronously with SDADC1 (not used)
265.// SDADC_SoftwareStartInjectedConv( SDADC1 );
266. 
267. // Launches regular conversion synchronously with SDADC1
268. SDADC_SoftwareStartConv( SDADC1 );
269.}
270. 
271.// ADC data process - simple mean
272. 
273.void adc3d_adc_process( void )
274.{
275. uint16_t i;
276. float summx, summy, summz;
277. 
278. //swap X-Y axis and reverse Z orientation divide by 2
279. for( i=0, summx=0.0, summy=0.0, summz=0.0; i < ADC3D_RAW_LEN; i++ )
280.  {
281.   summx += (float)(adc3d_raw_x[i]);
282.   summy += (float)(adc3d_raw_y[i]);
283.   summz += (float)(adc3d_raw_z[i]);
284.  }
285. adc3d_out_x = (summx / ADC3D_RAW_LEN);
286. adc3d_out_y = (summy / ADC3D_RAW_LEN);
287. adc3d_out_z = (summz / ADC3D_RAW_LEN);
288.}
289. 
290.// -- unused code rejected --
291. 
292./* eof */


Luck to you!

Outcomes