cpu/samd5x: avoid the use of bitfields#20714
Conversation
a6c028a to
6324c2a
Compare
|
Why? - I think bitfields are more legible, so there must be a reason. |
I'm not happy either but that's a needed step to tackle on our side if we want to add support to newer MCUs from Microchip at some point. |
cpu/samd5x/periph/can.c
Outdated
| DEBUG_PUTS("Extended ID"); | ||
| dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.ID = frame->can_id & CAN_EFF_MASK; | ||
| dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.XTD = 1; | ||
| dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.reg |= CAN_TXBE_0_ID(frame->can_id & CAN_EFF_MASK) |
There was a problem hiding this comment.
if bitfield operations are removed make them one write
assembble the whole id -> then write it
cpu/samd5x/periph/can.c
Outdated
| uint8_t tx_err_cnt = (uint8_t)(dev->conf->can->ECR.reg & CAN_ECR_TEC_Msk); | ||
| DEBUG("tx error counter = %u\n", tx_err_cnt); | ||
| uint8_t rx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.REC; | ||
| uint8_t rx_err_cnt = (uint8_t)((dev->conf->can->ECR.reg & CAN_ECR_REC_Msk) |
cpu/samd5x/periph/can.c
Outdated
| uint8_t tx_err_cnt = (uint8_t)(dev->conf->can->ECR.reg & CAN_ECR_TEC_Msk); | ||
| DEBUG("tx error counter = %u\n", tx_err_cnt); | ||
| uint8_t rx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.REC; | ||
| uint8_t rx_err_cnt = (uint8_t)((dev->conf->can->ECR.reg & CAN_ECR_REC_Msk) | ||
| >> CAN_ECR_REC_Pos); |
|
but the registers also changed name and from being a union of bitfield and reg to just a uint |
Yes. But I'd like to proceed in small steps for now. I am expecting breakages and it will be easier to deal with those if we do it step by step. |
2de511f to
6324c2a
Compare
|
@kfessel I've added a variable here and there to avoid multiple read of the same register. I hope I didn't miss some. |
There was a problem hiding this comment.
we need more of this (.reg & REG_Msk) >> REG_Pos
seems like the other way around is hidden in these MACROS (i did not check)
I for sure have missed some places where this is needed.
@ microchip: this makes the code so much easier to read and write
|
@kfessel I've addressed the new round of review. |
| uint32_t reg = dev->conf->can->ECR.reg; | ||
| uint8_t tx_err_cnt = (uint8_t) (reg & CAN_ECR_TEC_Msk); | ||
| DEBUG("tx error counter = %u\n", tx_err_cnt); | ||
| uint8_t rx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.REC; | ||
| uint8_t rx_err_cnt = (uint8_t)((reg & CAN_ECR_REC_Msk) >> CAN_ECR_REC_Pos); | ||
| DEBUG("rx error counter = %u\n", rx_err_cnt); | ||
| /* Check the CAN error type */ | ||
| uint8_t error_code = (uint8_t)dev->conf->can->PSR.bit.LEC; | ||
| uint8_t error_code = (uint8_t)(dev->conf->can->PSR.reg & CAN_PSR_LEC_Msk); |
There was a problem hiding this comment.
it is allready done here so copy
|
Latest round of review was addressed. |
|
May I squash this one ? |
|
look good please squash |
Signed-off-by: Dylan Laduranty <[email protected]>
43bbcac to
bfadc44
Compare
|
Rebased and squashed. |
maribu
left a comment
There was a problem hiding this comment.
Thx a bunch!
This will actually result in more efficient machine code, as a few instances of subsequent accesses of bit-fields of the same word in memory (marked as volatile) were replaced by loading that word into a temporary (non volatile) variable, from which the fields were extracted via bit-masks. The volatile qualifier prevents the optimizer to combine memory accesses. But in the new code, the temporary variable could be allocated as a register resulting in fewer memory accesses. Quite cool!
I have an style suggestion inline. Please squash directly if you agree, or just hit merge if you don't.
| const uint32_t flags = (OSCCTRL_DPLLSTATUS_CLKRDY | OSCCTRL_DPLLSTATUS_LOCK); | ||
| while (!((OSCCTRL->Dpll[idx].DPLLSTATUS.reg & flags) == flags)) {} |
There was a problem hiding this comment.
This will even be more efficient. I believe normally, the optimizer would combine the two bit-field accesses on the same word to a single memory access. But since those registers are marked as volatile, the compiler is not allowed to combine memory accesses.
| uint16_t rx_get_idx = 0; | ||
| uint16_t rx_put_idx = 0; | ||
| rx_get_idx = (dev->conf->can->RXF0S.reg >> CAN_RXF0S_F0GI_Pos) & 0x3F; | ||
| uint32_t reg = dev->conf->can->RXF0S.reg; |
There was a problem hiding this comment.
Again, this will produce more efficient machine code :)
| dev->conf->can->IR.reg |= CAN_IR_PEA; | ||
| /* Extract the Tx and Rx error counters */ | ||
| uint8_t tx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.TEC; | ||
| uint32_t reg = dev->conf->can->ECR.reg; |
There was a problem hiding this comment.
And another instance of better machine code :)
bfadc44 to
f36e6eb
Compare
f36e6eb to
8e2369f
Compare
|
Fixed extra character added by mistake after a semicolon. |
Signed-off-by: Dylan Laduranty <[email protected]>
8e2369f to
26b3583
Compare
|
🎉 |
|
Thanks for the reviews ! With this one merged, the first step of the migration is now completed. |
Contribution description
This PR replaces all calls of
foo->bar.bit.xyz = ABCDtofoo->bar.reg &= ABCDfor all SAMD5x MCUsThis should not have much impact on the code but it would be good to test the CAN driver implementation as I might have break something.
Testing procedure
A careful review especially on the CAN driver is needed?
CI should catch most of the failure but feel free to run some tests on hardware.
Issues/PRs references
see #20457