Hello Forum,
I'am porting a USB base driver from 16Bit CISC MCU to Cortex M3 MCU.
For set/clear peripheral registers at the CISC MCU I've used C-Standard RMW Operations (|=, &=) which resulted in atomic bit operations.
During porting I’ve used the also the RMW operations, because some registers are used exclusively in the interrupt context, there is no context switch. So my thought is that RMW is sufficient for set/clear bits in peripheral register.
Example this shows the problem:
This instruction sequence ( Bit Clear) fails to clear the interrupt factor (including asm mixed mode view)
*EPnS0 &= ~MASK_EPS_DRQ; // Interrupt bestätigen 0x4ea8: 0xf8ba 0x1000 LDRH.W R1, [R10] 0x4eac: 0xf64f 0x30ff MOVW R0, #64511 ; 0xfbff 0x4eb0: 0x4001 ANDS R1, R1, R0 0x4eb2: 0xf8aa 0x1000 STRH.W R1, [R10] *EPnS0 |= MASK_EPS_DRQIE; // Sendeinterrupt einschalten 0x4eb6: 0xf8ba 0x0000 LDRH.W R0, [R10] 0x4eba: 0xf450 0x4080 ORRS.W R0, R0, #16384 ; 0x4000 0x4ebe: 0xf8aa 0x0000 STRH.W R0, [R10]
This instruction sequence do the job correctly:
bFM3_USB0_EP1S_DRQ = 0; 0x4ec2: 0x2000 MOVS R0, #0 0x4ec4: 0xf8df 0x17e4 LDR.W R1, [PC, #0x7e4] ; 0x428429a8 (1115957672) 0x4ec8: 0x6008 STR R0, [R1] bFM3_USB0_EP1S_DRQIE = 1; 0x4eca: 0x2001 MOVS R0, #1 0x4ecc: 0xf8df 0x17e0 LDR.W R1, [PC, #0x7e0] ; 0x428429b8 (1115957688) 0x4ed0: 0x6008 STR R0, [R1] 0x4ed2: 0xe00c B.N 0x4eee
The MPU Setup for the MCU peripheral Area is
// Peripherals + 32Mbyte Bit band alias MPU->RBAR = ARM_MPU_RBAR(3, 0x40000000); MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_64MB);
As far as I know bit banding is necessary to prevent race conditions between shared context accesses of any memory/peripheral area. The section decribed above is only access during the peripherals interrupt Handler.
Why the RMW Operations fails and bit band operation do the correct job in this case?
Regards
Lorenz
Hello,
I’ve investigated further and found a situation where this function is called from main application and interrupt context, where enabling the DRQ bit causes an interrupt call immediate.
A rewrite of the sequence solves this problem:
*EPnS0 &= ~MASK_EPS_DRQ; // Packet Transfer Interrupt Request bit __DSB(); // whenever a memory access needs to have completed before program execution progresses. *EPnS0 |= MASK_EPS_DRQIE; // Packet Transfer Interrupt Enable bit
But why the __DSB instruction helps to clear the Packet Transfer Interrupt Request bit ?
regards,
NB:
my setup of the peripheral region is:
MPU->RNR = 3; MPU->RBAR = ARM_MPU_RBAR(3, 0x40000000); // Set region 3 to adress 0x40000000 MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_64MB);
where ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_64MB) does the following:
DisableExec: 1 AccessPermission: 3 TypeExtField: 0 IsShareable: 1 IsCacheable: 0 IsBufferable: 1 SubRegionDisable: 0 Size: 64MB according to The Definitive Guide to the ARM ® Cortex-M3 this setup should be correct (peripheral regions can be programmed as shared devices (TEX = b000, C = 0, B = 1)
The Register Bit Field Attributes are: