-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cpu/samd5x: avoid the use of bitfields #20714
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
@@ -440,19 +440,22 @@ static int _send(candev_t *candev, const struct can_frame *frame) | |||
|
|||
if (frame->can_id & CAN_EFF_FLAG) { | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one read
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one read
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <dylan.laduranty@mesotic.com>
43bbcac
to
bfadc44
Compare
Rebased and squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
@@ -708,26 +725,30 @@ static void _isr(candev_t *candev) | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this will produce more efficient machine code :)
@@ -847,12 +873,13 @@ static void _isr(candev_t *candev) | |||
DEBUG_PUTS("protocol error in arbitration phase"); | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <dylan.laduranty@mesotic.com>
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 = ABCD
tofoo->bar.reg &= ABCD
for 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