HWA
Bare metal programming with style
24cxx.h
Go to the documentation of this file.
1 
2 /* This file is part of the HWA project.
3  * Copyright (c) 2020 Christophe Duparquet.
4  * All rights reserved. Read LICENSE.TXT for details.
5  */
6 
63 /* _24cxx, name, twi, sla, as, ps
64  *
65  * as: address size (larger EEPROM devices (from 24C32) have 16-bit address)
66  * ps: page size
67  */
68 
69 #define HW_24CXX(...) _HW_24CXX0(__VA_ARGS__,,,,,,,,,)
70 #define _HW_24CXX0(k1,v1,k2,v2,k3,v3,k4,v4,eol,...) \
71  HW_B(_HW_24CXX0_,_hw_is_interfaceaddressaddresssizepagesize_##k1##k2##k3##k4##eol)(k1,v1,k2,v2,k3,v3,k4,v4)
72 #define _HW_24CXX0_0(...) \
73  ,HW_24CXX(...),"HW_24CXX(...)" must be defined as "HW_24CXX(interface,...,address,...,addresssize,...,pagesize,...)"
74 #define _HW_24CXX0_1(k1,twi,k2,sla,k3,as,k4,ps) _HW_24CXX1(HW_XO(twi),sla,as,ps)
75 #define _HW_24CXX1(...) _HW_24CXX2(__VA_ARGS__)
76 //#define _HW_24CXX_03(otwi,sla,as,ps) _24cxx,24cxx_##otwi,(otwi,sla,as,ps)
77 #define _HW_24CXX2(x,...) _HW_B(_HW_24CXX3_,x)(x,__VA_ARGS__)
78 #define _HW_24CXX3_1(z,o,e,...) ,o,e
79 #define _HW_24CXX3_0(c,o,d,sla,as,ps) _24cxx,24cxx_##o,(o,sla,as,ps)
80 
81 #define hw_class__24cxx
82 
83 #define _hw_is_interfaceaddressaddresssizepagesize_interfaceaddressaddresssizepagesize , 1
84 
85 
91 #define HW_DECLARE__24cxx , _hw_dc24cxx
92 
93 #define _hw_dc24cxx(o,twi,sla,as,ps,...) HW_BV(_hw_dc24cxx,declare_,HW_A0(__VA_ARGS__),o)
94 #define _hw_dc24cxx0(v,o) HW_E(HW_EM_OVL(v,(weak)))
95 #define _hw_dc24cxx1(weak,o) \
96  uint8_t _hw_##o##_read_bytes ( uint8_t, uint8_t, uint16_t, int, uint8_t* ) weak ; \
97  uint8_t _hw_##o##_write_page ( uint8_t, uint8_t, uint8_t, uint16_t, int, const uint8_t* ) weak ; \
98  uint8_t _hw_##o##_write_bytes ( uint8_t, uint8_t, uint8_t, uint16_t, int, const uint8_t* ) weak ; \
99  extern uint8_t hw_foo()
100 
106 #define HW_IMPLEMENT__24cxx , _hw_im24cxx
107 
108 #define _hw_im24cxx(o,twi,...) \
109  _hw_im24cxx_read_bytes(twi) \
110  _hw_im24cxx_write_page(twi) \
111  _hw_im24cxx_write_bytes(twi) \
112  extern uint8_t hw_foo()
113 
114 
130 #define hw_read__24cxx , _hw_rd24cxx
131 
132 #define _hw_rd24cxx(...) _hw_rd24cxx0(__VA_ARGS__,,,,,,)
133 
134 #define _hw_rd24cxx0(o,twi,sla,as,ps,ka,va,ks,vs,kb,vb,eol,...) \
135  HW_B(_hw_rd24cxx0,_hw_is_addresssizebuffer_##ka##ks##kb##eol)(o,twi,sla,as,ka,va,ks,vs,kb,vb,eol)
136 #define _hw_rd24cxx00(o,twi,sla,as,ka,va,ks,vs,kb,vb,eol) \
137  HW_E(HW_EM_SY("hw(read,object,address,..., size,..., buffer,... )"))
138 #define _hw_rd24cxx01(o,twi,sla,as,ka,va,ks,vs,kb,vb,eol) \
139  _hw_24cxx_##twi##_read_bytes(sla,as,va,vs,(uint8_t*)vb)
140 
141 
142 
143 #define _hw_im24cxx_read_bytes(twi) \
144  uint8_t _hw_24cxx_##twi##_read_bytes ( uint8_t sla, uint8_t as, uint16_t addr, int len, uint8_t *buf ) \
145  { \
146  uint8_t _twst ; \
147  uint8_t _sla ; \
148  uint8_t rv = 0 ; \
149  \
150  if ( as == 2 ) \
151  _sla = sla | ((addr >> 8) & 0x07); \
152  else \
153  _sla = sla ; \
154  \
155  begin: \
156  hw( xfr_start, twi ); \
157  \
158  while( !hw(read,(twi,irq)) ) {} \
159  switch( (_twst=hw(stat,twi)) ) \
160  { \
161  case HW_TWI_START: \
162  case HW_TWI_REP_START: \
163  break; \
164  \
165  case HW_TWI_MT_ARB_LOST: \
166  goto begin; \
167  \
168  default: \
169  goto error ; \
170  } \
171  \
172  hw( xfr_slaw, twi, _sla>>1 ); \
173  while( !hw(read,(twi,irq)) ) {} \
174  switch( (_twst=hw(stat,twi)) ) \
175  { \
176  case HW_TWI_MT_SLA_ACK: \
177  break; \
178  \
179  case HW_TWI_MT_ARB_LOST: \
180  goto begin; \
181  \
182  default: \
183  goto error; \
184  } \
185  \
186  if ( as == 2 ) { \
187  hw( xfr_write, twi, addr >> 8 ); \
188  while( !hw(read,(twi,irq)) ) {} \
189  switch( (_twst=hw(stat,twi)) ) \
190  { \
191  case HW_TWI_MT_DATA_ACK: \
192  break; \
193  \
194  case HW_TWI_MT_DATA_NACK: \
195  goto quit; \
196  \
197  case HW_TWI_MT_ARB_LOST: \
198  goto begin; \
199  \
200  default: \
201  goto error; \
202  } \
203  } \
204  \
205  hw( xfr_write, twi, addr & 255 ); \
206  while( !hw(read,(twi,irq)) ) {} \
207  switch( (_twst=hw(stat,twi)) ) \
208  { \
209  case HW_TWI_MT_DATA_ACK: \
210  break; \
211  \
212  case HW_TWI_MT_DATA_NACK: \
213  goto quit; \
214  \
215  case HW_TWI_MT_ARB_LOST: \
216  goto begin; \
217  \
218  default: \
219  goto error; \
220  } \
221  \
222  hw( xfr_start, twi ); \
223  while( !hw(read,(twi,irq)) ) {} \
224  switch( (_twst=hw(stat,twi)) ) \
225  { \
226  case HW_TWI_START: \
227  case HW_TWI_REP_START: \
228  break; \
229  \
230  case HW_TWI_MT_ARB_LOST: \
231  goto begin; \
232  \
233  default: \
234  goto error; \
235  } \
236  \
237  hw( xfr_slar, twi, sla & 127 ); \
238  while( !hw(read,(twi,irq)) ) {} \
239  switch( (_twst=hw(stat,twi)) ) \
240  { \
241  case HW_TWI_MR_SLA_ACK: \
242  break; \
243  \
244  case HW_TWI_MR_SLA_NACK: \
245  goto quit; \
246  \
247  case HW_TWI_MR_ARB_LOST: \
248  goto begin; \
249  \
250  default: \
251  goto error; \
252  } \
253  \
254  for ( ; len>0 ; len-- ) { \
255  if (len == 1) \
256  hw( xfr_read, twi, nack ); \
257  else \
258  hw( xfr_read, twi, ack ); \
259  \
260  while( !hw(read,(twi,irq)) ) {} \
261  switch( (_twst=hw(stat,twi)) ) \
262  { \
263  case HW_TWI_MR_DATA_NACK: \
264  len = 0; \
265  case HW_TWI_MR_DATA_ACK: \
266  *buf++ = hw(read,twi); \
267  rv++; \
268  if(_twst == HW_TWI_MR_DATA_NACK) \
269  goto quit; \
270  break; \
271  \
272  default: \
273  goto error; \
274  } \
275  } \
276  \
277  error: \
278  quit: \
279  hw( xfr_stop, twi ); \
280  return rv; \
281  }
282 
283 
299 #define hw_write__24cxx , _hw_wr24cxx
300 
301 #define _hw_is_addresssizebuffer_addresssizebuffer , 1
302 
303 #define _hw_wr24cxx(...) _hw_wr24cxx0(__VA_ARGS__,,,,,,)
304 #define _hw_wr24cxx0(o,twi,sla,as,ps,ka,va,ks,vs,kb,vb,eol,...) \
305  HW_B(_hw_wr24cxx0,_hw_is_addresssizebuffer_##ka##ks##kb##eol)(o,twi,sla,as,ps,ka,va,ks,vs,kb,vb,eol)
306 #define _hw_wr24cxx00(o,twi,sla,as,ps,ka,va,ks,vs,kb,vb,eol) \
307  HW_E(HW_EM_SY("hw(write,object,address,..., size,..., buffer,... )"))
308 #define _hw_wr24cxx01(o,twi,sla,as,ps,ka,va,ks,vs,kb,vb,eol) \
309  _hw_24cxx_##twi##_write_bytes(sla,as,ps,va,vs,(const uint8_t*)vb)
310 
311 
312 #define _hw_im24cxx_write_page(twi) \
313  uint8_t _hw_24cxx_##twi##_write_page ( uint8_t sla, uint8_t as, uint8_t ps, uint16_t addr, int len, const uint8_t *buf ) \
314  { \
315  uint8_t _twst ; \
316  uint8_t _sla ; \
317  uint8_t rv = 0; \
318  uint16_t endaddr; \
319  \
320  if (addr + len <= (addr | (ps - 1))) \
321  endaddr = addr + len; \
322  else \
323  endaddr = (addr | (ps - 1)) + 1; \
324  len = endaddr - addr; \
325  \
326  if ( as == 2 ) \
327  _sla = sla | ((addr >> 8) & 0x07); \
328  else \
329  _sla = sla ; \
330  \
331  begin: \
332  hw( xfr_start, twi ); \
333  while( !hw(read,(twi,irq)) ) {} \
334  switch( (_twst=hw(stat,twi)) ) \
335  { \
336  case HW_TWI_REP_START: \
337  case HW_TWI_START: \
338  break; \
339  \
340  case HW_TWI_MT_ARB_LOST: \
341  goto begin; \
342  \
343  default: \
344  goto error ; \
345  } \
346  \
347  hw( xfr_slaw, twi, _sla>>1 ); \
348  while( !hw(read,(twi,irq)) ) {} \
349  switch( (_twst=hw(stat,twi)) ) \
350  { \
351  case HW_TWI_MT_SLA_ACK: \
352  break; \
353  \
354  case HW_TWI_MT_ARB_LOST: \
355  goto begin; \
356  \
357  default: \
358  goto error; \
359  } \
360  \
361  if ( as == 2 ) { \
362  hw( xfr_write, twi, addr>>8 ); \
363  while( !hw(read,(twi,irq)) ) {} \
364  switch( (_twst=hw(stat,twi)) ) \
365  { \
366  case HW_TWI_MT_DATA_ACK: \
367  break; \
368  \
369  case HW_TWI_MT_DATA_NACK: \
370  goto quit; \
371  \
372  case HW_TWI_MT_ARB_LOST: \
373  goto begin; \
374  \
375  default: \
376  goto error; \
377  } \
378  } \
379  \
380  hw( xfr_write, twi, addr ); \
381  while( !hw(read,(twi,irq)) ) {} \
382  switch( (_twst=hw(stat,twi)) ) \
383  { \
384  case HW_TWI_MT_DATA_ACK: \
385  break; \
386  \
387  case HW_TWI_MT_DATA_NACK: \
388  goto quit; \
389  \
390  case HW_TWI_MT_ARB_LOST: \
391  goto begin; \
392  \
393  default: \
394  goto error; \
395  } \
396  \
397  \
398  for ( ; len>0 ; len-- ) { \
399  \
400  hw( xfr_write, twi, (*buf++) ); \
401  \
402  while( !hw(read,(twi,irq)) ) {} \
403  switch( (_twst=hw(stat,twi)) ) \
404  { \
405  case HW_TWI_MT_DATA_NACK: \
406  goto error; \
407  \
408  case HW_TWI_MT_DATA_ACK: \
409  rv++; \
410  break; \
411  \
412  default: \
413  goto error; \
414  } \
415  } \
416  \
417  error: \
418  quit: \
419  hw( xfr_stop, twi ); \
420  return rv; \
421  }
422 
423 
424 #define _hw_im24cxx_write_bytes(twi) \
425  uint8_t _hw_24cxx_##twi##_write_bytes ( uint8_t sla, uint8_t as, uint8_t ps, \
426  uint16_t eeaddr, int len, const uint8_t *buf) \
427  { \
428  uint8_t rv, total; \
429  \
430  total = 0; \
431  do \
432  { \
433  rv = _hw_24cxx_##twi##_write_page( sla, as, ps, eeaddr, len, buf); \
434  if (rv == (uint8_t)-1) \
435  return -1; \
436  \
437  eeaddr += rv; \
438  len -= rv; \
439  buf += rv; \
440  total += rv; \
441  } \
442  while (len > 0); \
443  \
444  return total; \
445  }