[ell-i-developers] Re: Behaviour of writing to read-only bits.

  • From: Pekka Nikander <pekka.nikander@xxxxxx>
  • To: ell-i-developers@xxxxxxxxxxxxx
  • Date: Fri, 31 Jan 2014 20:37:21 +0200

> The problem is that through the initialisation routine, it also writes a 
> value (commonly zero if it was not specified) to all the registers between 
> the base register and the last register referenced.
> 
> To use two initialization records, one for the first registers, and another 
> for the AFRx. It is doable as the system already supports two initialization 
> records apart from RCC. -> this will increase 3 bytes for the extra 
> initialization record, but reduce the InitRecordArray from 10 bytes to 6 
> bytes (two arrays, one of 4 and one of 2), what would lead to a reduction of 
> one byte in storage. 

Very good thinking, I think you solved it just right.

> Another option I imagine was to use some kind of Value+Offset approach, but 
> an efficient implementation could be tricky, as it needs two tables for space 
> efficiency. 

Actually it should not be that tricky if we go to C++11, where we can use const 
variables as constant expressions.  Something like the following.

#define D32O(p, r, v) \
  static const uint8_t  __port_ ## p ## _reg_ ## r ## _offset = offsetof(p, r); 
\
  static const uint32_t __port_ ## p ## _reg_ ## r ## _value = v

#define D32_OFFSET(p, r) __port_ ## p ## _reg_ ## r ## _offset
#define D32_VALUE(p, r)  __port_ ## p ## _reg_ ## r ## _value

#define DEFINE_PERI_INIT_RECORD(port) \
const SystemInitRecordData32Offset PERI ## port ## _INIT_DefaultRecords[] = { \
  IF(values) { \
    D32_VALUE(port, CR1), D32_VALUE(port, CR2), ... 
  }, 
  IF(offfsets) { \
    D32_OFFSET(port, CR1), D32_OFFSET(port, CR2), ...

Not as nice as we have now for the others, but still hides part of the 
ugliness.  Perhaps we could come up with something even better with C++11 
constexprs and the explicit initialisation list type, but I still don't 
understand well enough how one could generate initialisation lists with 
compile-time evaluation.
  
It might even be possible to first generate compile-time-only const structs for 
each register separately, and then use constexpr constructors to collect them 
into a the real data structure.

Something like this, perhaps:

struct __foo { const uint8_t offset_, const uint32_t value_ };

// Note the new C++11 initialisation list in the following
#define D32O(p, r, v) static const __foo __foo ## p ## r { offsetof(p, r), (v) }

#define DEFINE_PER_INIT_RECORD(port) \
  const SystemIinitRecordData32Offset \
    PERI ## port ## _INIT_DefaultRecords(port, { __foo ## port ## CR1, ... } )

where SystemInitRecordData32Offset has a suitable constexpr constructor.

But that is not trivial.

--Pekka


Other related posts: