HWA
Bare metal programming with style
iob_2.h
Go to the documentation of this file.
1 
2 /* This file is part of the HWA project.
3  * Copyright (c) 2021 Christophe Duparquet.
4  * All rights reserved. Read LICENSE.TXT for details.
5  */
6 
12 #define _hw_actions__iob , (configure,read,toggle,write)
13 #define _hwa_actions__iob , (configure,toggle,write)
14 
41 #define hw_configure__iob , _hw_cfiob
42 #define _hw_cfiob(o,p,...) \
43  do { \
44  uint8_t __attribute__((unused)) af=0xFF, mode=0xFF, pupd=0xFF, otype=0xFF, ospeed=0xFF ; \
45  struct { uint8_t commit ; hwa_gpb_t p ; } hwa_st ; \
46  hwa_t *hwa = (hwa_t*)&hwa_st ; \
47  _hwa_setup_o(p); \
48  _hwa_cfiob_(o,p,__VA_ARGS__); \
49  hwa_st.commit = 1 ; _hwa_commit_o(p); \
50  }while(0)
51 
52 #define hwa_configure__iob , _hwa_cfiob
53 #define _hwa_cfiob(...) \
54  do{ \
55  uint8_t __attribute__((unused)) af=0xFF, mode=0xFF, pupd=0xFF, otype=0xFF, ospeed=0xFF ; \
56  _hwa_cfiob_(__VA_ARGS__); \
57  }while(0)
58 
59 
60 #define _hwa_cfiob_(o,p,bn,bp,k,...) HW_BW(_hwa_cfiobfn,function,k)(o,p,bn,bp,k,__VA_ARGS__)
61 
62 #define _hwa_cfiobfn0(o,p,bn,bp,k,...) HW_BW(_hwa_cfiobmd,mode,k)(df,o,p,bn,bp,k,__VA_ARGS__)
63 /*
64  * Function
65  */
66 #define _hwa_cfiobfn1(o,p,bn,bp,k,v,...) HW_BW(_hwa_cfiobfn1,gpio,v)(o,p,bn,bp,v,__VA_ARGS__)
67 /*
68  * GPIO
69  */
70 #define _hwa_cfiobfn11(o,p,bn,bp,v,k,...) HW_BW(_hwa_cfiobmd,mode,k)(df,o,p,bn,bp,k,__VA_ARGS__)
71 /*
72  * Alternate?
73  */
74 #define _hwa_cfiobfn10(o,p,bn,bp,...) HW_BW(_hwa_cfiobfn2,1,bn)(o,p,bn,bp,__VA_ARGS__)
75 /*
76  * Can't set alternate function to multiple pins
77  */
78 #define _hwa_cfiobfn20(o,p,bn,bp,...) HW_E(HW_EM_CANTREMAP)
79 /*
80  * Single pin, is function '(...)'?
81  */
82 #define _hwa_cfiobfn21(o,p,bn,bp,v,...) HW_BP(_hwa_cfiobfn3,v)(o,p,bn,bp,v,__VA_ARGS__)
83 /*
84  * Function is '(...)', insert expanded signal name (assume there's only 2 elements).
85  */
86 #define _hwa_cfiobfn31(o,p,bn,bp,v,...) _hwa_cfiobfn32(o,p,bn,bp,HW_G2 v,v,__VA_ARGS__)
87 #define _hwa_cfiobfn32(...) _hwa_cfiobfn4(__VA_ARGS__)
88 /*
89  * Function is not '(...)', copy signal name
90  */
91 #define _hwa_cfiobfn30(o,p,bn,bp,v,...) _hwa_cfiobfn4(o,p,bn,bp,v,v,__VA_ARGS__)
92 /*
93  * Verify function name for pin
94  */
95 #define _hwa_cfiobfn4(o,p,bn,bp,vx,v,...) HW_BV(_hwa_cfiobfn4,af_##o##_,vx,v,o) (o,p,bn,bp,__VA_ARGS__)//PUSH
96 #define _hwa_cfiobfn40(vx,v,o) HW_E(HW_EM_XNIL(v,_hw_af_##o)) HW_EAT//POP
97 #define _hwa_cfiobfn41(r,v,o) af=r; _hwa_cfiobfn42//POP
98 #define _hwa_cfiobfn42(o,p,bn,bp,k,...) HW_BW(_hwa_cfiobmd,mode,k)(af,o,p,bn,bp,k,__VA_ARGS__)
99 /*
100  * 'mode'. Can drop 'o'.
101  */
102 #define _hwa_cfiobmd0(f,o,p,bn,bp,k,v,...) HW_E(HW_EM_AN(k,mode))
103 
104 #define _hwa_cfiobmd1(...) _hwa_cfiobmd2(__VA_ARGS__)
105 #define _hwa_cfiobmd2(f,o,p,bn,bp,k,v,...) HW_BV(_hwa_cfiobmd2,cfiob_##f##_,v,)(p,bn,bp,__VA_ARGS__)//PUSH
106 #define _hwa_cfiobmd20(v,...) \
107  HW_E(HW_EM_VAL(v,mode,(digital_input,digital_input_floating,digital_input_pullup, \
108  digital_input_pulldown,analog_input,digital_output, \
109  digital_output_pushpull, digital_output_opendrain))) HW_EAT//POP
110 #define _hwa_cfiobmd21(v,...) v//POP
111 /*
112  * Default/alternate function
113  *
114  * mode otype ospeed pupd
115  *
116  * 0 input 0 push-pull 0 low 0 none
117  * 1 output 1 open-drain 1 medium 1 pull-up
118  * 2 alt func 2 fast 2 pull-down
119  * 3 analog 3 high
120  *
121  * , code branch
122  */
123 #define _hw_cfiob_df_digital_input , mode=0; _hwa_cfiob9
124 #define _hw_cfiob_df_digital_input_floating , mode=0; pupd=0; _hwa_cfiob9
125 #define _hw_cfiob_df_digital_input_pullup , mode=0; pupd=1; _hwa_cfiob9
126 #define _hw_cfiob_df_digital_input_pulldown , mode=0; pupd=2; _hwa_cfiob9
127 #define _hw_cfiob_df_digital_output , mode=1; _hwa_cfiobfq
128 #define _hw_cfiob_df_digital_output_pushpull , mode=1; otype=0; _hwa_cfiobfq
129 #define _hw_cfiob_df_digital_output_opendrain , mode=1; otype=1; _hwa_cfiobfq
130 #define _hw_cfiob_df_analog_input , mode=3; _hwa_cfiob9
131 
132 #define _hw_cfiob_af_digital_input , mode=2; _hwa_cfiob9
133 #define _hw_cfiob_af_digital_input_floating , mode=2; pupd=0; _hwa_cfiob9
134 #define _hw_cfiob_af_digital_input_pullup , mode=2; pupd=1; _hwa_cfiob9
135 #define _hw_cfiob_af_digital_input_pulldown , mode=2; pupd=2; _hwa_cfiob9
136 #define _hw_cfiob_af_digital_output , mode=2; _hwa_cfiobfq
137 #define _hw_cfiob_af_digital_output_pushpull , mode=2; otype=0; _hwa_cfiobfq
138 #define _hw_cfiob_af_digital_output_opendrain , mode=2; otype=1; _hwa_cfiobfq
139 #define _hw_cfiob_af_analog_input , mode=2; _hwa_cfiob9
140 
141 /*
142  * Optionnal argument 'frequency' (only for output modes)
143  */
144 #define _hw_cfiob_fq_lowest , 0
145 #define _hw_cfiob_fq_low , 0
146 #define _hw_cfiob_fq_medium , 1
147 #define _hw_cfiob_fq_fast , 2
148 #define _hw_cfiob_fq_high , 3
149 #define _hw_cfiob_fq_highest , 3
150 
151 #define _hwa_cfiobfq(p,bn,bp,k,...) HW_BW(_hwa_cfiobfq,frequency,k)(p,bn,bp,k,__VA_ARGS__)
152 #define _hwa_cfiobfq0(p,bn,bp,k,...) HW_B(_hwa_cfiobfq0,k)(p,bn,bp,k,__VA_ARGS__)
153 #define _hwa_cfiobfq01(p,bn,bp,k,...) _hwa_do_cfiob( &hwa->p, bn, bp, af, mode, pupd, otype, ospeed )
154 #define _hwa_cfiobfq00(p,bn,bp,k,...) HW_E(HW_EM_AN(k,frequency))
155 
156 #define _hwa_cfiobfq1(p,bn,bp,k,v,...) HW_BV(_hwa_cfiobfq1,cfiob_fq_,v,)(p,bn,bp,__VA_ARGS__)//PUSH
157 #define _hwa_cfiobfq11(r,...) ospeed=r; _hwa_cfiob9//POP
158 #define _hwa_cfiobfq10(v,...) HW_E(HW_EM_VAL(v,frequency,(lowest,2MHz,10MHz,50MHz,highest))) HW_EAT//POP
159 
160 #define _hwa_cfiob9(p,bn,bp,...) HW_B(_hwa_cfiob9,__VA_ARGS__)(p,bn,bp,__VA_ARGS__)
161 #define _hwa_cfiob90(p,bn,bp,g,...) HW_E(HW_EM_G(g))
162 #define _hwa_cfiob91(p,bn,bp,g,...) _hwa_do_cfiob( &hwa->p, bn, bp, af, mode, pupd, otype, ospeed )
163 
164 
165 HW_INLINE void _hwa_do_cfiob_( hwa_gpb_t *p, uint8_t i,
166  uint8_t af, uint8_t mode, uint8_t pupd, uint8_t otype, uint8_t ospeed )
167 {
168  uint32_t mask, value ;
169 
170  if ( af != 0xFF ) {
171  value = af ;
172  if ( i < 8 ) {
173  mask = 0x0F<<(4*i);
174  value <<= (4*i);
175  p->afrl.mmask |= mask ;
176  p->afrl.mvalue = (p->afrl.mvalue & ~mask) | value ;
177  }
178  else {
179  mask = 0x0F<<(4*(i-8));
180  value <<= (4*(i-8));
181  p->afrh.mmask |= mask ;
182  p->afrh.mvalue = (p->afrh.mvalue & ~mask) | value ;
183  }
184  }
185 
186  if ( mode != 0xFF ) {
187  value = mode ;
188  mask = 3UL<<(2*i);
189  value <<= (2*i);
190  p->mode.mmask |= mask ;
191  p->mode.mvalue = (p->mode.mvalue & ~mask) | value ;
192  }
193 
194  if ( otype != 0xFF ) {
195  value = otype ;
196  mask = 1UL<<i;
197  value <<= i;
198  p->otype.mmask |= mask ;
199  p->otype.mvalue = (p->otype.mvalue & ~mask) | value ;
200  }
201 
202  if ( ospeed != 0xFF ) {
203  value = ospeed ;
204  mask = 3UL<<(2*i);
205  value <<= (2*i);
206  p->ospeed.mmask |= mask ;
207  p->ospeed.mvalue = (p->ospeed.mvalue & ~mask) | value ;
208  }
209 
210  if ( pupd != 0xFF ) {
211  value = pupd ;
212  mask = 3UL<<(2*i);
213  value <<= (2*i);
214  p->pupd.mmask |= mask ;
215  p->pupd.mvalue = (p->pupd.mvalue & ~mask) | value ;
216  }
217 }
218 
219 
220 HW_INLINE void _hwa_do_cfiob( hwa_gpb_t *p, uint8_t bn, uint8_t bp,
221  uint8_t af, uint8_t mode, uint8_t pupd, uint8_t otype, uint8_t ospeed )
222 {
223  uint16_t mask = ((1UL<<bn)-1)<<bp ;
224  if ( mask & 0x0001 ) _hwa_do_cfiob_(p, 0,af,mode,pupd,otype,ospeed);
225  if ( mask & 0x0002 ) _hwa_do_cfiob_(p, 1,af,mode,pupd,otype,ospeed);
226  if ( mask & 0x0004 ) _hwa_do_cfiob_(p, 2,af,mode,pupd,otype,ospeed);
227  if ( mask & 0x0008 ) _hwa_do_cfiob_(p, 3,af,mode,pupd,otype,ospeed);
228  if ( mask & 0x0010 ) _hwa_do_cfiob_(p, 4,af,mode,pupd,otype,ospeed);
229  if ( mask & 0x0020 ) _hwa_do_cfiob_(p, 5,af,mode,pupd,otype,ospeed);
230  if ( mask & 0x0040 ) _hwa_do_cfiob_(p, 6,af,mode,pupd,otype,ospeed);
231  if ( mask & 0x0080 ) _hwa_do_cfiob_(p, 7,af,mode,pupd,otype,ospeed);
232  if ( mask & 0x0100 ) _hwa_do_cfiob_(p, 8,af,mode,pupd,otype,ospeed);
233  if ( mask & 0x0200 ) _hwa_do_cfiob_(p, 9,af,mode,pupd,otype,ospeed);
234  if ( mask & 0x0400 ) _hwa_do_cfiob_(p,10,af,mode,pupd,otype,ospeed);
235  if ( mask & 0x0800 ) _hwa_do_cfiob_(p,11,af,mode,pupd,otype,ospeed);
236  if ( mask & 0x1000 ) _hwa_do_cfiob_(p,12,af,mode,pupd,otype,ospeed);
237  if ( mask & 0x2000 ) _hwa_do_cfiob_(p,13,af,mode,pupd,otype,ospeed);
238  if ( mask & 0x4000 ) _hwa_do_cfiob_(p,14,af,mode,pupd,otype,ospeed);
239  if ( mask & 0x8000 ) _hwa_do_cfiob_(p,15,af,mode,pupd,otype,ospeed);
240 }
241 
242 
243 
253 #define hw_read__iob , _hw_rdiob
254 #define _hw_rdiob(o,p,bn,bp,...) HW_B(_hw_rdiob_,__VA_ARGS__)(p,bn,bp,__VA_ARGS__,)
255 #define _hw_rdiob_0(p,bn,bp,g,...) HW_E(HW_EM_G(g))
256 #define _hw_rdiob_1(p,bn,bp,...) ( (_hw_read(p,idr) & ((1UL<<bn)-1)) >> bp )
257 
258 
273 /* Use the BSRR instead of a read-modify-write on the ODR.
274  */
275 #define hw_toggle__iob , _hw_tgiob
276 #define _hw_tgiob(o,p,bn,bp,g,...) HW_B(_hw_tgiob_,g)(p,bn,bp,g)
277 #define _hw_tgiob_0(p,bn,bp,g) HW_E(HW_EM_G(g))
278 #define _hw_tgiob_1(p,bn,bp,g) \
279  do { \
280  uint32_t v = _hw_read(p,odr); \
281  if ( bn==1 ) { \
282  _hw_write( p, bsrr, v<<16 | ~v ); \
283  } \
284  else { \
285  uint32_t mask = ((1UL<<bn)-1)<<bp ; \
286  _hw_write( p, bsrr, (v&mask)<<16 | (~v&mask) ); \
287  } \
288  }while(0)
289 
290 
300 #define hwa_toggle__iob , _hwa_tgiob
301 #define _hwa_tgiob(o,p,bn,bp,g,...) HW_B(_hwa_tgiob_,g)(p,bn,bp,g)
302 #define _hwa_tgiob_0(p,bn,bp,g) HW_E(HW_EM_G(g))
303 #define _hwa_tgiob_1(p,bn,bp,g) hwa->p.toggles |= (((1UL<<bn)-1) << bp)
304 
305 
319 /* Writing pins can be done two ways:
320  * * writing the ODR
321  * * writing the BSRR (or BRR)
322  *
323  * Writing the BSRR allows atomic writing of the ODR's bits without leading to
324  * a heavier binary code. So, let's use that!
325  *
326  * BSRR: MSB16 bits reset the ODR bits
327  * LSB16 bits set the ODR bits, it has the priority over MSB16
328  */
329 #define hw_write__iob , _hw_wriob
330 #define _hw_wriob(o,p,bn,bp,v,g,...) HW_B(_hwx_wriob1_,v)(_hw,p,bn,bp,v,g)
331 
332 #define hwa_write__iob , _hwa_wriob
333 #define _hwa_wriob(o,p,bn,bp,v,g,...) HW_B(_hwx_wriob1_,v)(_hwa,p,bn,bp,v,g)
334 
335 #define _hwx_wriob1_1(x,p,bn,bp,v,g) HW_E(HW_EM_V)
336 #define _hwx_wriob1_0(x,p,bn,bp,v,g) HW_B(_hwx_wriob2_,g)(x,p,bn,bp,v,g)
337 #define _hwx_wriob2_0(x,p,bn,bp,v,g) HW_E(HW_EM_G(g))
338 #define _hwx_wriob2_1(x,p,bn,bp,v,g) \
339  { uint32_t v32 = (v); /* v could be volatile, boolean expr... */ \
340  x##_write_m( p, bsrr, 0xffffffff, \
341  ((((1UL<<bn)-1)<<bp) & (~v32)<<bp)<<16 | \
342  ((((1UL<<bn)-1)<<bp) & ( v32)<<bp) ); }