-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadc.c
More file actions
457 lines (377 loc) · 13.8 KB
/
Copy pathadc.c
File metadata and controls
457 lines (377 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
/* adc.c -- system layer
** Copyright (c) 2020-2026 Renaud Fivet
**
** ADC for temperature sensor and Vrefint
** interrupt based serial transmission
** clocks configuration: HSI, HSE, PLL HSI, PLL HSE
** implements system.h interface: uptime, init(), kputc(), kputs(), yield()
** uptime = seconds elapsed since boot
** Serial tx, SysClck 8MHz HSI based, baudrate 9600, Busy wait transmission
** user LED toggled every second
** SysTick interrupt every second
*/
#include "system.h" /* implements system.h */
typedef volatile unsigned long register_t ;
/** CORE **********************************************************************/
extern struct {
register_t csr ;
register_t rvr ;
register_t cvr ;
register_t calib ;
} systick ; /* 0xE000E010 */
extern struct {
register_t iser ;
} nvic ; /* 0xE000E100 */
#define unmask_irq( idx) nvic.iser = 1 << idx
#define USART1_IRQ_IDX 27
/** PERIPH ********************************************************************/
#define CAT( a, b) a##b
#define HEXA( a) CAT( 0x, a)
#define RCC_CR_HSION 0x00000001 /* 1: Internal High Speed clock enable */
#define RCC_CR_HSEON 0x00010000 /* 16: External High Speed clock enable */
#define RCC_CR_HSERDY 0x00020000 /* 17: External High Speed clock ready flag */
#define RCC_CR_PLLON 0x01000000 /* 24: PLL enable */
#define RCC_CR_PLLRDY 0x02000000 /* 25: PLL clock ready flag */
#define RCC_CFGR_SW_MSK 0x00000003 /* 1-0: System clock SWitch Mask */
#define RCC_CFGR_SW_HSE 0x00000001 /* 1-0: Switch to HSE as system clock */
#define RCC_CFGR_SW_PLL 0x00000002 /* 1-0: Switch to PLL as system clock */
#define RCC_CFGR_SWS_MSK 0x0000000C /* 3-2: System clock SWitch Status Mask */
#define RCC_CFGR_SWS_HSE 0x00000004 /* 3-2: HSE used as system clock */
#define RCC_CFGR_SWS_PLL 0x00000008 /* 3-2: PLL used as system clock */
#define RCC_CFGR_PLLSRC 0x00010000
#define RCC_CFGR_PLLSRC_HSI 0x00000000 /* HSI / 2 */
#define RCC_CFGR_PLLSRC_HSE 0x00010000 /* HSE */
#define RCC_CFGR_PLLXTPRE 0x00020000
#define RCC_CFGR_PLLXTPRE_DIV1 0x00000000 /* HSE */
#define RCC_CFGR_PLLXTPRE_DIV2 0x00020000 /* HSE / 2 */
#define RCC_CFGR_PLLMUL_MSK (0x00F << 18)
#define RCC_CFGR_PLLMUL( v) ((v - 2) << 18)
#define RCC_AHBENR_IOPxEN( h) (1 << (17 + HEXA( h) - 0xA))
#define RCC_APB2ENR_USART1EN 0x00004000 /* 14: USART1 clock enable */
#define RCC_APB2ENR_ADCEN 0x00000200 /* 9: ADC clock enable */
#define RCC_CR2_HSI14ON 0x00000001 /* 1: HSI14 clock enable */
#define RCC_CR2_HSI14RDY 0x00000002 /* 2: HSI14 clock ready */
extern struct {
register_t cr ;
register_t cfgr ;
register_t cir ;
register_t apb2rstr ;
register_t apb1rstr ;
register_t ahbenr ;
register_t apb2enr ;
register_t apb1enr ;
register_t bdcr ;
register_t csr ;
register_t ahbrstr ;
register_t cfgr2 ;
register_t cfgr3 ;
register_t cr2 ;
} rcc ; /* 0x40021000 */
typedef struct {
register_t moder ;
register_t otyper ;
register_t ospeedr ; /* B..F */
register_t pupdr ;
register_t idr ;
register_t odr ;
register_t bsrr ;
register_t lckr ;
register_t afrl ;
register_t afrh ;
register_t brr ;
} gpio_t ;
extern gpio_t gpioa ; /* 0x48000000 */
#define ADC_ISR_ADRDY 1 /* 0: ADC Ready */
#define ADC_ISR_EOC 4 /* 2: End Of Conversion flag */
#define ADC_CR_ADEN 1 /* 0: ADc ENable command */
#define ADC_CR_ADSTART 4 /* 2: ADC Start Conversion command */
#define ADC_CR_ADCAL (1 << 31) /* 31: ADC Start Calibration cmd */
#define ADC_CFGR1_SCANDIR 4 /* 2: Scan sequence direction */
#define ADC_CFGR1_DISCEN (1 << 16) /* 16: Enable Discontinuous mode */
#define ADC_CFGR2_CKMODE (3 << 30) /* 31-30: Clock Mode Mask */
/* 31-30: Default 00 HSI14 */
#define ADC_CFGR2_PCLK2 (1 << 30) /* 31-30: PCLK/2 */
#define ADC_CFGR2_PCLK4 (2 << 30) /* 31-30: PCLK/4 */
#define ADC_CCR_VREFEN (1 << 22) /* 22: Vrefint Enable */
#define ADC_CCR_TSEN (1 << 23) /* 23: Temperature Sensor Enable */
extern struct {
register_t isr ; /* 0 Interrupt and Status Register */
register_t ier ; /* 1 Interrupt Enable Register */
register_t cr ; /* 2 Control Register */
register_t cfgr1 ; /* 3 Configuration Register 1 */
register_t cfgr2 ; /* 4 Configuration Register 2 */
register_t smpr ; /* 5 Sampling Time Register */
register_t _rsv0[ 2] ;
register_t tr ; /* 8 Watchdog Threshold Register */
register_t _rsv1 ;
register_t chselr ; /* 10 Channel Selection Register */
register_t _rsv2[ 5] ;
register_t dr ; /* 16 Data Register */
register_t _rsv3[ 177] ;
register_t ccr ; /* 194 Common Configuration Register */
} adc ; /* 0x40012400 */
#define USART_CR1_TXEIE (1 << 7) /* 7: TDR Empty Interrupt Enable */
#define USART_CR1_TE 8 /* 3: Transmit Enable */
//#define USART_CR1_RE 4 /* 2: Receive Enable */
#define USART_CR1_UE 1 /* 0: USART Enable */
#define USART_ISR_TXE (1 << 7) /* 7: Transmit Data Register Empty */
typedef struct {
register_t cr1 ; /* Config Register */
register_t cr2 ;
register_t cr3 ;
register_t brr ; /* Baudrate Register */
long _reserved_ ;
register_t rtor ;
register_t rqr ;
register_t isr ; /* Interrupt and Status Register */
register_t icr ;
register_t rdr ;
register_t tdr ; /* Transmit Data Register */
} usart_t ;
extern usart_t usart1 ; /* 0x40013800 */
/** SYSTEM MEMORY *************************************************************/
/* STM32F030 calibration addresses (at 3.3V and 30C) */
extern const short ts_cal1 ; /* 0x1FFFF7B8 */
extern const short vrefint_cal ; /* 0x1FFFF7BA */
/* user LED ON:
Board LED_IOP LED_PIN LED_ON
No LED undefined
V1.1/Baite a 4 0
V2.00 a 4 1
Nucleo a 5 1
vcc-gnd b 1 0
Discovery c 8 or 9 1
*/
#define LED_IOP a
#define LED_PIN 4
#define LED_ON 0
#ifdef LED_ON
# define GPIO( x) CAT( gpio, x)
extern gpio_t GPIO( LED_IOP) ; /* gpioa: 0x48000000, gpiob: 0x48000400 */
/* gpioc: 0x48000800 */
#endif
/* 8MHz quartz, configure PLL at 24MHz */
#define HSE 8000000
// #define HSEPRE 4
#define PLL 6
#define BAUD 9600
//#define HSI14 1
#ifdef PLL
# ifdef HSE
# ifdef HSEPRE
# define CLOCK HSE / HSEPRE * PLL
# else
# define CLOCK HSE / 2 * PLL
# endif
# else /* HSI */
# define CLOCK 8000000 / 2 * PLL
# endif
# if CLOCK < 16000000
# error PLL output below 16MHz
# endif
#elif defined( HSE)
# define CLOCK HSE
#else /* HSI */
# define CLOCK 8000000
#endif
#if CLOCK > 48000000
# error clock frequency exceeds 48MHz
#endif
#if CLOCK % BAUD
# warning baud rate not accurate at that clock frequency
#endif
static unsigned char txbuf[ 8] ; // best if size is a power of 2 for cortex-M0
#define TXBUF_SIZE (sizeof txbuf / sizeof txbuf[ 0])
static unsigned char txbufin ;
static volatile unsigned char txbufout ;
void USART1_Handler( void) {
if( txbufout == txbufin) {
/* Empty buffer => Disable TXEIE */
usart1.cr1 &= ~USART_CR1_TXEIE ;
} else {
static unsigned char lastc ;
unsigned char c ;
c = txbuf[ txbufout] ;
if( c == '\n' && lastc != '\r')
c = '\r' ;
else
txbufout = (txbufout + 1) % TXBUF_SIZE ;
usart1.tdr = c ;
lastc = c ;
}
}
void kputc( unsigned char c) { /* character output */
int nextidx ;
/* Wait if buffer full */
nextidx = (txbufin + 1) % TXBUF_SIZE ;
while( nextidx == txbufout)
yield() ;
txbuf[ txbufin] = c ;
txbufin = nextidx ;
/* Trigger transmission by enabling interrupt */
usart1.cr1 |= USART_CR1_TXEIE ;
}
int kputs( const char s[]) { /* string output */
int cnt = 0 ;
int c ;
while( (c = *s++) != 0) {
kputc( c) ;
cnt += 1 ;
}
return cnt ;
}
void yield( void) { /* give way */
__asm( "WFI") ; /* Wait for System Tick Interrupt */
}
volatile unsigned uptime ; /* seconds elapsed since boot */
#ifdef LED_ON
static void userLEDtoggle( void) {
GPIO( LED_IOP).odr ^= 1 << LED_PIN ; /* toggle User LED */
}
#endif
void SysTick_Handler( void) {
uptime += 1 ;
#ifdef LED_ON
userLEDtoggle() ;
#endif
}
const short *adc_init( unsigned channels) {
/* Enable ADC peripheral */
rcc.apb2enr |= RCC_APB2ENR_ADCEN ;
/* Setup ADC sampling clock */
#if HSI14
rcc.cr2 |= RCC_CR2_HSI14ON ; /* Start HSI14 clock */
do {} while( !( rcc.cr2 & RCC_CR2_HSI14RDY)) ; /* Wait for stable clock */
/* Select HSI14 as sampling clock for ADC */
// adc.cfgr2 &= ~ADC_CFGR2_CKMODE ; /* Default 00 == HSI14 */
#elif CLOCK <= 28000000
/* Select PCLK/2 as sampling clock for ADC */
// adc.cfgr2 |= ADC_CFGR2_PCLK2 ; /* 01 PCLK/2 Over default 00 */
adc.cfgr2 = ADC_CFGR2_PCLK2 ; /* 01 PCLK/2 Over default 00 */
#else
// adc.cfgr2 |= ADC_CFGR2_PCLK4 ; /* 10 PCLK/4 Over default 00 */
adc.cfgr2 = ADC_CFGR2_PCLK4 ; /* 10 PCLK/4 Over default 00 */
#endif
/* Calibration */
adc.cr |= ADC_CR_ADCAL ;
do {} while( adc.cr & ADC_CR_ADCAL) ; /* Wait end of calibration */
/* Enable Command (below Work Around from Errata necessary with PCLK/4) */
do {
adc.cr |= ADC_CR_ADEN ;
} while( !( adc.isr & ADC_ISR_ADRDY)) ;
/* Select inputs, precision and scan direction */
adc.chselr = channels ;
// adc.smpr = 4 ; /* 4 is 41.5 ADC clock cycles */
// adc.smpr = 5 ; /* 5 is 55.5 ADC clock cycles */
// adc.smpr = 6 ; /* 6 is 71.5 ADC clock cycles */
adc.smpr = 7 ; /* 7 is 239.5 ADC clock cycles */
adc.ccr |= (channels & (1 << 17)) << 5 ; /* VREFEN */
adc.ccr |= (channels & (1 << 16)) << 7 ; /* TSEN */
/* Default scan direction (00) is Temperature before Voltage */
// adc.cfgr1 |= 8 ; /* 10 bits */
// adc.cfgr1 &= ~ADC_CFGR1_SCANDIR ; /* Default 0 is low to high */
adc.cfgr1 |= ADC_CFGR1_SCANDIR ; /* high to low */
adc.cfgr1 |= ADC_CFGR1_DISCEN ; /* Enable Discontinuous mode */
return &ts_cal1 ;
}
unsigned adc_convert( void) {
/* Either only one channel in sequence or Discontinuous mode ON */
adc.cr |= ADC_CR_ADSTART ; /* Start ADC conversion */
do {} while( adc.cr & ADC_CR_ADSTART) ; /* Wait for start command cleared */
return adc.dr ;
}
void adc_vnt( vnt_cmd_t cmd, short *ptrV, short *ptrC) {
if( cmd == VNT_INIT)
adc_init( 3 << 16) ;
if( cmd <= VNT_CAL) {
/* Calibration Values */
*ptrV = vrefint_cal ;
*ptrC = ts_cal1 ;
return ;
}
/* ADC Conversion */
*ptrV = adc_convert() ; // * 4 ;
*ptrC = adc_convert() ; // * 4 ;
if( cmd == VNT_VNC) {
*ptrC = 300 + (ts_cal1 - *ptrC * vrefint_cal / *ptrV) * 10000 / 5336 ;
*ptrV = 330 * vrefint_cal / *ptrV ;
}
}
int init( void) {
/* By default SYSCLK == HSI [8MHZ] */
#ifdef HSE
/* Start HSE clock (8 MHz external oscillator) */
rcc.cr |= RCC_CR_HSEON ;
/* Wait for oscillator to stabilize */
do {} while( (rcc.cr & RCC_CR_HSERDY) == 0) ;
#endif
#ifdef PLL
/* Setup PLL HSx/2 * 6 [24MHz] */
/* Default 0: PLL HSI/2 src, PLL MULL * 2 */
# ifdef HSE
rcc.cfgr = RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_DIV2 |
RCC_CFGR_PLLMUL( PLL) ;
# ifdef HSEPRE
rcc.cfgr2 = HSEPRE - 1 ; /* Bit 0 overwrites RCC_CFGR_PLLXTPRE_DIV2 */
# endif
# else
rcc.cfgr = RCC_CFGR_PLLMUL( PLL) ;
# endif
rcc.cr |= RCC_CR_PLLON ;
do {} while( (rcc.cr & RCC_CR_PLLRDY) == 0) ; /* Wait for PLL */
/* Switch to PLL as system clock SYSCLK == PLL [24MHz] */
rcc.cfgr = (rcc.cfgr & ~RCC_CFGR_SW_MSK) | RCC_CFGR_SW_PLL ;
do {} while( (rcc.cfgr & RCC_CFGR_SWS_MSK) != RCC_CFGR_SWS_PLL) ;
#elif defined( HSE)
/* Switch to HSE as system clock SYSCLK == HSE [8MHz] */
rcc.cfgr = (rcc.cfgr & ~RCC_CFGR_SW_MSK) | RCC_CFGR_SW_HSE ;
do {} while( (rcc.cfgr & RCC_CFGR_SWS_MSK) != RCC_CFGR_SWS_HSE) ;
#endif
#ifdef HSE
/* Switch off HSI */
rcc.cr &= ~RCC_CR_HSION ;
#endif
/* SYSTICK */
#if CLOCK > 0x1000000
# define TICKDIV 8
# define TICKSRC 0 /* STK_CSR_CLKSOURCE == HCLK / 8 */
#else
# define TICKDIV 1
# define TICKSRC 4 /* STK_CSR_CLKSOURCE == HCLK */
#endif
systick.rvr = (CLOCK / TICKDIV) - 1 ;
systick.cvr = 0 ;
systick.csr = TICKSRC | 3 ; /* CLKSOURCE, Interrupt ON, Enable */
/* SysTick_Handler will execute every 1s from now on */
#ifdef LED_ON
/* User LED ON */
rcc.ahbenr |= RCC_AHBENR_IOPxEN( LED_IOP) ; /* Enable IOPx periph */
GPIO( LED_IOP).moder |= 1 << (LED_PIN * 2) ; /* Output [01], over default 00 */
/* OTYPER Push-Pull by default */
/* PxN output default LOW at reset */
# if LED_ON
userLEDtoggle() ;
# endif
#endif
/* USART1 9600 8N1 */
rcc.ahbenr |= RCC_AHBENR_IOPxEN( a) ; /* Enable GPIOA periph */
gpioa.moder |= 0x0A << (9 * 2) ; /* PA9-10 ALT 10, over default 00 */
gpioa.afrh |= 0x110 ; /* PA9-10 AF1 0001, over default 0000 */
rcc.apb2enr |= RCC_APB2ENR_USART1EN ;
usart1.brr = CLOCK / BAUD ; /* PCLK is default source */
usart1.cr1 |= USART_CR1_UE | USART_CR1_TE ; /* Enable USART & Tx */
/* Unmask USART1 irq */
unmask_irq( USART1_IRQ_IDX) ;
kputs(
#ifdef PLL
"PLL"
#endif
#ifdef HSE
"HSE"
#else
"HSI"
#endif
"\n") ;
return 0 ;
}
/* end of adc.c */