HWA
Bare metal programming with style
ioa_2.h
Go to the documentation of this file.
1 
2 /* This file is part of the HWA project.
3  * Copyright (c) 2017 Christophe Duparquet.
4  * All rights reserved. Read LICENSE.TXT for details.
5  */
6 
12 #define hw_read__ioa , _hw_rdioa
13 #define hw_write__ioa , _hw_wrioa
14 #define hwa_write__ioa , _hwa_wrioa
15 #define hw_toggle__ioa , _hw_tgioa
16 #define hwa_toggle__ioa , _hwa_tgioa
17 
18 #define hw_actions__ioa , (configure,read,toggle,write)
19 #define hwa_actions__ioa , (configure,toggle,write)
20 
77 /* Immediate action: create a local minimal context, apply the actions for each
78  * pin on it, and commit. Do not handle signal remapping.
79  */
80 #define hw_configure__ioa , _hw_cfioa
81 #define _hw_cfioa(o,p,...) \
82  do { \
83  uint8_t __attribute__((unused)) cnf, mode, odr=0 ; \
84  struct { uint8_t commit ; hwa_gpa_t p ; hwa_afioa_t afio ; } hwa_st ; \
85  hwa_t *hwa = (hwa_t*)&hwa_st ; \
86  _hwa_setup_o(p); \
87  _hwa_cfioa_(0,o,p,__VA_ARGS__,); \
88  hwa_st.commit = 1 ; _hwa_commit_o(p); \
89  }while(0)
90 
91 /* Transaction. Handle signals remapping.
92  * TODO: verify how errors are triggered at different levels of parsing
93  */
94 #define hwa_configure__ioa , _hwa_cfioa
95 #define _hwa_cfioa(o,p,bn,...) _HW_B(_hwa_cfioa,_hw_is_1_##bn)(o,p,bn,__VA_ARGS__,)
96 #define _hwa_cfioa0(...) do{ uint8_t cnf, mode, odr=0 ; _hwa_cfioa_(0,__VA_ARGS__); }while(0)
97 #define _hwa_cfioa1(o,p,bn,bp,...) \
98  do{ \
99  uint8_t __attribute__((unused)) cnf, mode, odr=0 ; \
100  _hwa_cfioa_(1,o,p,bn,bp,__VA_ARGS__); \
101  if ( hwa->map.error ) \
102  HWA_E(HW_EM_PMAP((o,bp))); \
103  }while(0)
104 
105 
106 /* The first argument 'x' is an indicator:
107  * 1: hwa(...) is used to configure one single pin and can process signal remaping;
108  * 0: hw(...) or multiple pins to configure -> signal remaping impossible.
109  */
110 #define _hwa_cfioa_(x,o,p,bn,bp,k,...) HW_BW(_hwa_cfioafn,function,k)(x,o,p,bn,bp,k,__VA_ARGS__)
111 #define _hwa_cfioafn0(x,o,p,bn,bp,k,...) HW_BW(_hwa_cfioamd,mode,k)(df,o,p,bn,bp,k,__VA_ARGS__)
112 
113 /* Function
114  */
115 #define _hwa_cfioafn1(x,o,p,bn,bp,k,v,...) HW_BW(_hwa_cfioafn1,gpio,v)(x,o,p,bn,bp,v,__VA_ARGS__)
116 /*
117  * GPIO
118  */
119 #define _hwa_cfioafn11(x,o,p,bn,bp,v,k,...) HW_BW(_hwa_cfioamd,mode,k)(df,o,p,bn,bp,k,__VA_ARGS__)
120 /*
121  * Alternate
122  */
123 #define _hwa_cfioafn10(x,o,p,bn,bp,...) _hwa_cfioafn2##x(o,p,bn,bp,__VA_ARGS__)
124 /*
125  * x==0, can't set alternate function
126  */
127 #define _hwa_cfioafn20(o,p,bn,bp,...) HW_E(HW_EM_CANTREMAP)
128 /*
129  * Is function '(...)'?
130  */
131 #define _hwa_cfioafn21(o,p,bn,bp,v,...) HW_BP(_hwa_cfioafn3,v)(o,p,bn,bp,v,__VA_ARGS__)
132 /*
133  * Function is '(...)', insert expanded signal name (assume there's only 2 elements).
134  */
135 #define _hwa_cfioafn31(o,p,bn,bp,v,...) _hwa_cfioafn32(o,p,bn,bp,HW_G2 v,v,__VA_ARGS__)
136 #define _hwa_cfioafn32(...) _hwa_cfioafn4(__VA_ARGS__)
137 /*
138  * Function is not '(...)', copy signal name
139  */
140 #define _hwa_cfioafn30(o,p,bn,bp,v,...) _hwa_cfioafn4(o,p,bn,bp,v,v,__VA_ARGS__)
141 /*
142  * Verify that there is a definition: _hw_af_<port_1_x>_<name>
143  */
144 #define _hwa_cfioafn4(o,p,bn,bp,vx,v,...) HW_B(_hwa_cfioafn4,_hw_af_##o##_##vx)(o,p,bn,bp,vx,v,__VA_ARGS__)
145 #define _hwa_cfioafn40(o,p,bn,bp,vx,v,...) HW_E(HW_EM_VAL(v,function,_hw_af_##o))
146 /*
147  * Record association of signal to pin. Verification and processing is made at commit time.
148  */
149 #define _hwa_cfioafn41(o,p,bn,bp,vx,v,k,...) \
150  if ( hwa->map.vx == 0 ) \
151  hwa->map.vx = HW_ADDRESS((p,bn,bp)); \
152  else if ( hwa->map.vx != HW_ADDRESS((p,bn,bp)) ) \
153  HWA_E(HW_EM_MAP); \
154  HW_BW(_hwa_cfioamd,mode,k)(af,o,p,bn,bp,k,__VA_ARGS__)
155 
156 #define _hwa_cfioamd0(f,o,p,bn,bp,k,...) HW_E(HW_EM_AN(k,mode))
157 
158 /* Mode. Can drop 'o'.
159  */
160 #define _hwa_cfioamd1(f,o,p,bn,bp,k,v,...) HW_BV(_hwa_cfioamd2,cfioa_##f##_,v,)(p,bn,bp,__VA_ARGS__)//PUSH
161 #define _hwa_cfioamd20(v,...) \
162  HW_E(HW_EM_VAL(v,mode,(digital_input,digital_input_floating,digital_input_pullup, \
163  digital_input_pulldown,analog_input,digital_output, \
164  digital_output_pushpull, digital_output_opendrain))) HW_EAT//POP
165 #define _hwa_cfioamd21(v,...) v//POP
166 /*
167  * Default/alternate function , code ; branch
168  */
169 #define _hw_cfioa_df_digital_input , cnf=1 ; mode=0 ; _hwa_cfioa9
170 #define _hw_cfioa_df_digital_input_floating , cnf=1 ; mode=0 ; _hwa_cfioa9
171 #define _hw_cfioa_df_digital_input_pullup , cnf=2 ; mode=0 ; odr=1 ; _hwa_cfioa9
172 #define _hw_cfioa_df_digital_input_pulldown , cnf=2 ; mode=0 ; odr=0 ; _hwa_cfioa9
173 #define _hw_cfioa_df_digital_output , cnf=0 ; _hwa_cfioafq
174 #define _hw_cfioa_df_digital_output_pushpull , cnf=0 ; _hwa_cfioafq
175 #define _hw_cfioa_df_digital_output_opendrain , cnf=1 ; _hwa_cfioafq
176 #define _hw_cfioa_df_analog_input , cnf=0 ; mode=0 ; _hwa_cfioa9
177 
178 #define _hw_cfioa_af_digital_input , cnf=1 ; mode=0 ; _hwa_cfioa9
179 #define _hw_cfioa_af_digital_input_floating , cnf=1 ; mode=0 ; _hwa_cfioa9
180 #define _hw_cfioa_af_digital_input_pullup , cnf=2 ; mode=0 ; odr=1 ; _hwa_cfioa9
181 #define _hw_cfioa_af_digital_input_pulldown , cnf=2 ; mode=0 ; odr=0 ; _hwa_cfioa9
182 #define _hw_cfioa_af_digital_output , cnf=2 ; _hwa_cfioafq
183 #define _hw_cfioa_af_digital_output_pushpull , cnf=2 ; _hwa_cfioafq
184 #define _hw_cfioa_af_digital_output_opendrain , cnf=3 ; _hwa_cfioafq
185 #define _hw_cfioa_af_analog_input , cnf=0 ; mode=0 ; _hwa_cfioa9
186 /*
187  * Optionnal argument 'frequency' (only for output modes)
188  */
189 #define _hwa_cfioafq(p,bn,bp,k,...) HW_BW(_hwa_cfioafq,frequency,k)(p,bn,bp,k,__VA_ARGS__)
190 
191 #define _hw_cfioa_fq_10MHz , 1
192 #define _hw_cfioa_fq_2MHz , 2
193 #define _hw_cfioa_fq_lowest , 2
194 #define _hw_cfioa_fq_50MHz , 3
195 #define _hw_cfioa_fq_highest , 3
196 
197 #define _hwa_cfioafq0(p,bn,bp,k,...) HW_B(_hwa_cfioafq0,k)(p,bn,bp,k,__VA_ARGS__)
198 #define _hwa_cfioafq01(p,bn,bp,k,...) mode=2 ; _hwa_do_cfioa( &hwa->p, bn, bp, cnf, mode, odr )
199 #define _hwa_cfioafq00(p,bn,bp,k,...) HW_E(HW_EM_AN(k,frequency))
200 
201 #define _hwa_cfioafq1(p,bn,bp,k,v,...) HW_B(_hwa_cfioafq2,_hw_cfioa_fq_##v)(p,bn,bp,v,__VA_ARGS__)
202 #define _hwa_cfioafq21(p,bn,bp,v,...) mode=HW_A1(_hw_cfioa_fq_##v); _hwa_cfioa9(p,bn,bp,__VA_ARGS__)
203 #define _hwa_cfioafq20(p,bn,bp,v,...) HW_E(HW_EM_VAL(v,frequency,(lowest,2MHz,10MHz,50MHz,highest)))
204 
205 #define _hwa_cfioa9(p,bn,bp,...) HW_B(_hwa_cfioa9,__VA_ARGS__)(p,bn,bp,__VA_ARGS__)
206 #define _hwa_cfioa90(p,bn,bp,g,...) HW_E(HW_EM_G(g))
207 #define _hwa_cfioa91(p,bn,bp,g,...) _hwa_do_cfioa( &hwa->p, bn, bp, cnf, mode, odr )
208 
209 
210 HW_INLINE void _hwa_do_cfioa_( uint8_t i, hwa_gpa_t *p, uint8_t cnf, uint8_t mode, uint8_t odr )
211 {
212  uint32_t m, v ;
213 
214  /* Pull-up & pull-down are driven by the ODR
215  */
216  if ( cnf==2 && mode==0 ) {
217  if ( odr == 0 )
218  m = 1UL<<(i+16) ;
219  else
220  m = 1UL<<i ;
221  p->bsrr.mmask |= m ;
222  p->bsrr.mvalue |= m ;
223  }
224 
225  v = (cnf<<2)|mode ;
226 
227  if ( i < 8 ) {
228  i *= 4 ;
229  m = 0x0FUL << i ;
230  v = v << i ;
231  p->crl.mmask |= m ;
232  p->crl.mvalue = (p->crl.mvalue & ~m) | (m & v) ;
233  }
234  else {
235  i -= 8 ;
236  i *= 4 ;
237  m = 0x0FUL << i ;
238  v = v << i ;
239  p->crh.mmask |= m ;
240  p->crh.mvalue = (p->crh.mvalue & ~m) | (m & v) ;
241  }
242 }
243 
244 
245 HW_INLINE void _hwa_do_cfioa( hwa_gpa_t *p, uint8_t bn, uint8_t bp, uint8_t cnf, uint8_t mode, uint8_t odr )
246 {
247  uint16_t mask = ((1UL<<bn)-1)<<bp ;
248  if ( mask & 0x0001 ) _hwa_do_cfioa_( 0,p,cnf,mode,odr);
249  if ( mask & 0x0002 ) _hwa_do_cfioa_( 1,p,cnf,mode,odr);
250  if ( mask & 0x0004 ) _hwa_do_cfioa_( 2,p,cnf,mode,odr);
251  if ( mask & 0x0008 ) _hwa_do_cfioa_( 3,p,cnf,mode,odr);
252  if ( mask & 0x0010 ) _hwa_do_cfioa_( 4,p,cnf,mode,odr);
253  if ( mask & 0x0020 ) _hwa_do_cfioa_( 5,p,cnf,mode,odr);
254  if ( mask & 0x0040 ) _hwa_do_cfioa_( 6,p,cnf,mode,odr);
255  if ( mask & 0x0080 ) _hwa_do_cfioa_( 7,p,cnf,mode,odr);
256  if ( mask & 0x0100 ) _hwa_do_cfioa_( 8,p,cnf,mode,odr);
257  if ( mask & 0x0200 ) _hwa_do_cfioa_( 9,p,cnf,mode,odr);
258  if ( mask & 0x0400 ) _hwa_do_cfioa_(10,p,cnf,mode,odr);
259  if ( mask & 0x0800 ) _hwa_do_cfioa_(11,p,cnf,mode,odr);
260  if ( mask & 0x1000 ) _hwa_do_cfioa_(12,p,cnf,mode,odr);
261  if ( mask & 0x2000 ) _hwa_do_cfioa_(13,p,cnf,mode,odr);
262  if ( mask & 0x4000 ) _hwa_do_cfioa_(14,p,cnf,mode,odr);
263  if ( mask & 0x8000 ) _hwa_do_cfioa_(15,p,cnf,mode,odr);
264 }
265 
266 
267 
276 #define _hw_rdioa(o,p,bn,bp,...) HW_B(_hw_rdioa_,__VA_ARGS__)(p,bn,bp,__VA_ARGS__,)
277 #define _hw_rdioa_0(p,bn,bp,g,...) HW_E(HW_EM_G(g))
278 #define _hw_rdioa_1(p,bn,bp,...) ( (_hw_read(p,idr) & ((1UL<<bn)-1)) >> bp )
279 
280 
293 /* Writing pins can be done two ways:
294  * * writing the ODR
295  * * writing the BSRR (or BRR)
296  *
297  * Writing the BSRR allows atomic writing of the ODR's bits without leading to
298  * a heavier binary code. So, let's use that!
299  *
300  * BSRR: MSB16 bits reset the ODR bits
301  * LSB16 bits set the ODR bits, it has the priority over MSB16
302  */
303 #define _hw_wrioa(o,p,bn,bp,v,g,...) HW_B(_hwx_wrioa1_,v)(_hw,p,bn,bp,v,g)
304 #define _hwa_wrioa(o,p,bn,bp,v,g,...) HW_B(_hwx_wrioa1_,v)(_hwa,p,bn,bp,v,g)
305 #define _hwx_wrioa1_1(x,p,bn,bp,v,g) HW_E(HW_EM_V)
306 #define _hwx_wrioa1_0(x,p,bn,bp,v,g) HW_B(_hwx_wrioa2_,g)(x,p,bn,bp,v,g)
307 #define _hwx_wrioa2_0(x,p,bn,bp,v,g) HW_E(HW_EM_G(g))
308 #define _hwx_wrioa2_1(x,p,bn,bp,v,g) \
309  { uint32_t v32 = (v); /* v could be volatile, boolean expr... */ \
310  x##_write_m( p, bsrr, 0xffffffff, \
311  ((((1UL<<bn)-1)<<bp) & (~v32)<<bp)<<16 | \
312  ((((1UL<<bn)-1)<<bp) & ( v32)<<bp) ); }
313 
314 
327 /* Use the BSRR instead of a read-modify-write on the ODR.
328  */
329 #define _hw_tgioa(o,p,bn,bp,g,...) HW_B(_hw_tgioa_,g)(p,bn,bp,g)
330 #define _hw_tgioa_0(p,bn,bp,g) HW_E(HW_EM_G(g))
331 #define _hw_tgioa_1(p,bn,bp,g) \
332  do { \
333  uint32_t v = _hw_read(p,odr); \
334  if ( bn==1 ) { \
335  _hw_write( p, bsrr, v<<16 | ~v ); \
336  } \
337  else { \
338  uint32_t mask = ((1UL<<bn)-1)<<bp ; \
339  _hw_write( p, bsrr, (v&mask)<<16 | (~v&mask) ); \
340  } \
341  }while(0)
342 
343 
353 #define _hwa_tgioa(o,p,bn,bp,g,...) HW_B(_hwa_tgioa_,g)(p,bn,bp,g)
354 #define _hwa_tgioa_0(p,bn,bp,g) HW_E(HW_EM_G(g))
355 #define _hwa_tgioa_1(p,bn,bp,g) hwa->p.toggles |= (((1UL<<bn)-1) << bp)