HWA
Bare metal programming with style
twia_2.h
Go to the documentation of this file.
1 
2 /* This file is part of the HWA project.
3  * Copyright (c) 2012,2015 Christophe Duparquet.
4  * All rights reserved. Read LICENSE.TXT for details.
5  */
6 
35 #define hw_configure__twia , _hw_cftwia
36 #define _hw_cftwia( o,a, ... ) _hw_cftwia_( _hw, o, __VA_ARGS__,, )
37 
38 #define hwa_configure__twia , _hwa_cftwia
39 #define _hwa_cftwia( o,a, ... ) _hw_cftwia_( _hwa, o, __VA_ARGS__,, )
40 
41 /* Optionnal argument `bps`
42  * The 'TWEN' bit that makes the TWI take control of the I/O pins
43  * is set by the 'xfr_' actions.
44  */
45 #define _hw_cftwia_(h,o,k,...) do { HW_BW(_hw_cftwiabps,bps,k)(h,o,k,__VA_ARGS__); }while(0)
46 #define _hw_cftwiabps0(h,o,k,...) HW_BW(_hw_cftwiasa,slave_address,k)(h,o,k,__VA_ARGS__)
47 #define _hw_cftwiabps1(h,o,k,v,...) HW_B(_hw_cftwiabps1,v)(h,o,v,__VA_ARGS__)
48 #define _hw_cftwiabps11(h,o,v,...) HW_E(HW_EM_VAM(bps))
49 #define _hw_cftwiabps10(h,o,v,k,...) \
50  uint32_t hw_bps=(v), br=0, psc=0, pscreg=0 ; \
51  float brpsc = ((1.0*HW_SYSHZ / hw_bps)-16)/2 ; \
52  if ( brpsc < 256 ) { \
53  psc = 1 ; \
54  pscreg = 0 ; \
55  br = (uint32_t)(0.5 + brpsc) ; \
56  if ( brpsc < 1 && HW_SYSHZ != hw_bps*(16+2*psc*br) ) \
57  HWA_E(HW_EM_XSO(v,bps)); /* value of bps unreachable */ \
58  } else if ( brpsc < 4*256 ) { \
59  psc = 4 ; \
60  pscreg = 1 ; \
61  br = (uint32_t)(0.5 + brpsc/4) ; \
62  } else if ( brpsc < 16*256 ) { \
63  psc = 16 ; \
64  pscreg = 2 ; \
65  br = (uint32_t)(0.5 + brpsc/16) ; \
66  } else if ( brpsc < 64*256 ) { \
67  psc = 64 ; \
68  pscreg = 3 ; \
69  br = (uint32_t)(0.5 + brpsc/64) ; \
70  } else \
71  HWA_E(HW_EM_XSO(v,bps)); /* value of bps too low */ \
72  h##_write( o, psc, pscreg ); \
73  h##_write( o, br, br ); \
74  HW_BW(_hw_cftwiasa,slave_address,k)(h,o,k,__VA_ARGS__)
75 
76 /* Optionnal argument `slave_address`
77  */
78 #define _hw_cftwiasa0(h,o,k,...) HW_BW(_hw_cftwiagc,general_call,k)(h,o,k,__VA_ARGS__)
79 #define _hw_cftwiasa1(h,o,k,v,...) HW_B(_hw_cftwiasa1,v)(h,o,v,__VA_ARGS__)
80 #define _hw_cftwiasa11(h,o,v,...) HW_E(HW_EM_VAM(slave_address))
81 #define _hw_cftwiasa10(h,o,v,k,...) \
82  uint8_t hw_sla=(v); \
83  if ( hw_sla < 0 || hw_sla > 127 ) \
84  HWA_E(HW_EM_VAL(v,slave_address,(0..127))); \
85  h##_write( o, sla, hw_sla ); \
86  HW_BW(_hw_cftwiagc,general_call,k)(h,o,k,__VA_ARGS__)
87 
88 /* Optionnal argument `general_call`
89  */
90 #define _hw_cftwiagc0 _hw_cftwiasam
91 #define _hw_cftwiagc1(h,o,k,v,...) HW_BV(_hw_cftwiagc1,state_,v,h,o) (h,o,__VA_ARGS__) // PUSH
92 #define _hw_cftwiagc10(v,...) HW_E(HW_EM_VOAST(v,general_call)) HW_EAT // POP
93 #define _hw_cftwiagc11(v,n,h,o) h##_write( o, gce, v); _hw_cftwiasam // POP
94 
95 
96 /* Optionnal argument `slave_address_mask`
97  */
98 #define _hw_cftwiasam(h,o,k,...) HW_BW(_hw_cftwiasam,slave_address_mask,k)(h,o,k,__VA_ARGS__)
99 #define _hw_cftwiasam0(h,o,...) HW_EOL(__VA_ARGS__)
100 #define _hw_cftwiasam1(h,o,k,v,...) HW_B(_hw_cftwia_vslam_,v)(h,o,v,__VA_ARGS__)
101 #define _hw_cftwiasam11(h,o,v,...) HW_E(HW_EM_VAM(slave_address_mask))
102 #define _hw_cftwiasam10(h,o,v,...) \
103  uint8_t hw_sam=(v); \
104  if ( hw_sam < 0 || hw_sam > 127 ) \
105  HWA_E(HW_EM_VAL(v,slave_address_mask,(0..127))); \
106  h##_write( o, slam, hw_sam ) HW_EOL(__VA_ARGS__)
107 
108 
109 /* Submitted by gotnone via GitHub */
121 #define hw_turn__twia , _hw_tntwia_
122 #define hwa_turn__twia , _hwa_tntwia_
123 
124 #define _hw_tntwia_(o,a, v, ...) HW_B(_hw_tntwia__,_hw_state_##v)(_hw,o,v,__VA_ARGS__)
125 #define _hwa_tntwia_(o,a, v, ...) HW_B(_hw_tntwia__,_hw_state_##v)(_hwa,o,v,__VA_ARGS__)
126 #define _hw_tntwia__0(h,o, v, ...) HW_E(HW_EM_ST(v))
127 #define _hw_tntwia__1(h,o, v, ...) h##_write(o, en, HW_A1(_hw_state_##v)) HW_EOL(__VA_ARGS__)
128 
129 
161 /* TODO:
162  * * create a relative '(TWI,bus)' to handle TWI bus operations?
163  * * use get/put for bus transfers?
164  *
165  * FIXME: could use a function 'hw_id(uint8_t v){ return v; }' to check the
166  * presence of a value so that '*ptr' would be OK?
167  * --> Could use surrounding parentheses.
168  *
169  * FIXME: bus_xfer_ack / bus_xfer_nack actions?
170  */
171 #define hw_xfr_start__twia , _hw_twia_txstart
172 #define _hw_twia_txstart(o,a,k,...) HW_BW(_hw_twiaend,irq,k)(o,ifenstart,k,__VA_ARGS__)
173 
174 
175 #define hw_xfr_stop__twia , _hw_twia_txstop
176 #define _hw_twia_txstop(o,a,k,...) HW_BW(_hw_twiaend,irq,k)(o,ifenstop,k,__VA_ARGS__)
177 
178 
179 #define hw_xfr_slaw__twia , _hw_twia_txslaw
180 #define _hw_twia_txslaw(o,a,v,k,...) \
181  do{ \
182  uint8_t hw_sla=(v); \
183  if ( hw_sla > 127 ) \
184  HWA_E(HW_EM_VAL(v,slave address,(0..127))); \
185  _hw_write(o,dr,(hw_sla<<1)+0); \
186  HW_BW(_hw_twiaend,irq,k)(o,ifen,k,__VA_ARGS__); \
187  }while(0)
188 
189 
190 #define hw_xfr_slar__twia , _hw_twia_txslar
191 #define _hw_twia_txslar(o,a,v,k,...) \
192  do{ \
193  uint8_t hw_sla=(v); \
194  if ( hw_sla > 127 ) \
195  HWA_E(HW_EM_VAL(v,slave address,(0..127))); \
196  _hw_write(o,dr,(hw_sla<<1)+1); \
197  HW_BW(_hw_twiaend,irq,k)(o,ifen,k,__VA_ARGS__); \
198  }while(0)
199 
200 #define hw_xfr_write__twia , _hw_twiawr
201 #define _hw_twiawr(o,a,v,k,...) \
202  do { \
203  _hw_write(o,dr,(v)); \
204  HW_BW(_hw_twiaend,irq,k)(o,ifen,k,__VA_ARGS__); \
205  } while(0)
206 
207 
208 #define hw_xfr_read__twia , _hw_twiard
209 #define _hw_twiard(o,a,k,...) HW_BW(_hw_twiardack,ack,k)(o,k,__VA_ARGS__,,)
210 #define _hw_twiardack1(o,ok,k,...) HW_BW(_hw_twiaend,irq,k)(o,ifenack,k,__VA_ARGS__)
211 #define _hw_twiardack0(o,k,...) HW_BW(_hw_twiardnack,nack,k)(o,k,__VA_ARGS__)
212 #define _hw_twiardnack1(o,ok,k,...) HW_BW(_hw_twiaend,irq,k)(o,ifen,k,__VA_ARGS__)
213 #define _hw_twiardnack0(o,k,...) HW_E(HW_EM_XNIL(k,(ack,nack)))
214 
215 
216 #define _hw_twiaend0(o,v,...) _hw_write(o,cr,_hw_twia_cr_##v) HW_EOL(__VA_ARGS__)
217 #define _hw_twiaend1(o,v,...) _hw_write(o,cr,_hw_twia_cr_##v##ie) HW_EOL(__VA_ARGS__)
218 
219 
229 #define hw_read__twia , _hw_rdtwia
230 #define _hw_rdtwia(o,a,...) _hw_read(o,dr) HW_EOL(__VA_ARGS__)
231 
232 
233 
248 #define hw_stat__twia , _hw_stat_twia
249 #define _hw_stat_twia(o,a,...) (_hw_read(o,sr)&0xF8) HW_EOL(__VA_ARGS__)
250 
251 
257 #define HW_TWI_START 0x08
258 
262 #define HW_TWI_REP_START 0x10
263 
268 #define HW_TWI_MT_SLA_ACK 0x18
269 
273 #define HW_TWI_MT_SLA_NACK 0x20
274 
278 #define HW_TWI_MT_DATA_ACK 0x28
279 
283 #define HW_TWI_MT_DATA_NACK 0x30
284 
288 #define HW_TWI_MT_ARB_LOST 0x38
289 
294 #define HW_TWI_MR_ARB_LOST 0x38
295 
299 #define HW_TWI_MR_SLA_ACK 0x40
300 
304 #define HW_TWI_MR_SLA_NACK 0x48
305 
309 #define HW_TWI_MR_DATA_ACK 0x50
310 
314 #define HW_TWI_MR_DATA_NACK 0x58
315 
320 #define HW_TWI_SR_SLA_ACK 0x60
321 
325 #define HW_TWI_SR_ARB_LOST_SLA_ACK 0x68
326 
330 #define HW_TWI_SR_GCALL_ACK 0x70
331 
336 #define HW_TWI_SR_ARB_LOST_GCALL_ACK 0x78
337 
341 #define HW_TWI_SR_DATA_ACK 0x80
342 
346 #define HW_TWI_SR_DATA_NACK 0x88
347 
351 #define HW_TWI_SR_GCALL_DATA_ACK 0x90
352 
356 #define HW_TWI_SR_GCALL_DATA_NACK 0x98
357 
361 #define HW_TWI_SR_STOP 0xA0
362 
367 #define HW_TWI_ST_SLA_ACK 0xA8
368 
372 #define HW_TWI_ST_ARB_LOST_SLA_ACK 0xB0
373 
377 #define HW_TWI_ST_DATA_ACK 0xB8
378 
382 #define HW_TWI_ST_DATA_NACK 0xC0
383 
387 #define HW_TWI_ST_LAST_DATA 0xC8
388 
393 #define HW_TWI_NO_INFO 0xF8
394 
398 #define HW_TWI_BUS_ERROR 0x00
399 
400 
401 
402 /*******************************************************************************
403  * *
404  * Context management *
405  * *
406  *******************************************************************************/
407 
408 #define _hwa_setup__twia(o,a) \
409  _hwa_setup_r( o, br ); \
410  _hwa_setup_r( o, cr ); \
411  _hwa_setup_r( o, sr ); \
412  _hwa_setup_r( o, ar ); \
413  _hwa_setup_r( o, amr )
414 
415 
416 #define _hwa_init__twia(o,a) \
417  _hwa_init_r( o, br, 0x00 ); \
418  _hwa_init_r( o, cr, 0x00 ); \
419  _hwa_init_r( o, sr, 0xF8 ); \
420  _hwa_init_r( o, ar, 0xFE ); \
421  _hwa_init_r( o, amr, 0x00 )
422 
423 
424 #define _hwa_commit__twia(o,a) \
425  _hwa_commit_r( o, br ); \
426  _hwa_commit_r( o, cr ); \
427  _hwa_commit_r( o, sr ); \
428  _hwa_commit_r( o, ar ); \
429  _hwa_commit_r( o, amr )
430 
431 
461 /*******************************************************************************
462  * *
463  * Implementation *
464  * *
465  *******************************************************************************/
466 
467 #define HW_DECLARE__twia , _hw_declare_twia
468 
469 #define _hw_declare_twia(o,a,...) \
470  void _hw_##o##_start_write_stop ( uint8_t sla, uint8_t v ); \
471  uint8_t _hw_##o##_start_read_stop ( uint8_t sla ) HW_EOL(__VA_ARGS__)
472 
473 
474 #define HW_IMPLEMENT__twia , _hw_define_twia
475 
476 #define _hw_define_twia(o,a,...) \
477  void _hw_##o##_start_write_stop ( uint8_t sla, uint8_t v ) \
478  { \
479  hw( xfr_start, o ); \
480  while( !hw( read, (o,irq) ) ) {} \
481  hw( xfr_slaw, o, sla & 0x7F ); \
482  while( !hw( read, (o,irq) ) ) {} \
483  hw( xfr_write, o, v ); \
484  while( !hw( read, (o,irq) ) ) {} \
485  hw( xfr_stop, o ); \
486  } \
487  \
488  uint8_t _hw_##o##_start_read_stop ( uint8_t sla ) \
489  { \
490  hw( xfr_start, o ); \
491  while( !hw( read, (o,irq) ) ) {} \
492  hw( xfr_slaw, o, sla & 0x7F ); \
493  while( !hw( read, (o,irq) ) ) {} \
494  hw( xfr_read, o, nack ); \
495  while( !hw( read, (o,irq) ) ) {} \
496  hw( xfr_stop, o ); \
497  \
498  return hw( read, o ); \
499  } \
500  \
501  extern uint8_t hw_foo() \
502  \
503  HW_EOL(__VA_ARGS__)