I have created an uint8_t
array which has data packed into a dense structure which the microcontroller parses to extract variables. I have found a workaround for now, but I am curious as to why my previous code might have failed.
The following function is what I was trying to use:
/*
* Input Configuration Buffer:
* Byte 0:
* Bit 0: Input Joystick Left (0) or Input Joystick Right (1)
* Bit 1: Invert X-Axis (1)
* Bit 2: Invert Y-Axis (1)
* Bit 3: Output Joystick Left (0) or Output Joystick Right (1)
* Bits 4-7: Don't Care
* Byte 1: X-Deadzone 4th-Byte (float)
* Byte 2: X-Deadzone 3rd-Byte (float)
* Byte 3: X-Deadzone 2nd-Byte (float)
* Byte 4: X-Deadzone 1st-Byte (float)
* Byte 5: Y-Deadzone 4th-Byte (float)
* Byte 6: Y-Deadzone 3rd-Byte (float)
* Byte 7: Y-Deadzone 2nd-Byte (float)
* Byte 8: Y-Deadzone 1st-Byte (float)
*/
void Controller_Config_MapInputJoystickAsJoystick(Controller_HandleTypeDef *c, uint8_t *ic_buffer){
uint8_t js_in = GET_BIT(ic_buffer[0], 0);
uint8_t invert_x = GET_BIT(ic_buffer[0], 1);
uint8_t invert_y = GET_BIT(ic_buffer[0], 2);
uint8_t js_out = GET_BIT(ic_buffer[0], 3);
float *deadzone_x = (float *)(&ic_buffer[1]);
float *deadzone_y = (float *)(&ic_buffer[5]);
float val_x = invert_x ? -joysticks[js_in].x.val : joysticks[js_in].x.val;
float val_y = invert_y ? -joysticks[js_in].y.val : joysticks[js_in].y.val;
if((val_x > *deadzone_x) || (val_x < -*deadzone_x)){
c->joysticks._bits[js_out*2 + 0] += (int16_t)(val_x * -INT16_MIN);
}
if((val_y > *deadzone_y) || (val_y < -*deadzone_y)){
c->joysticks._bits[js_out*2 + 1] += (int16_t)(val_y * -INT16_MIN);
}
}
When this code runs, it seems to run fine until it tries to compare (val_x > *deadzone_x) || (val_x < -*deadzone_x)
. At this point, the microcontroller enters a HardFault condition.
This code is compiled as (asm):
ldr r3, [r7, #24]
vldr s15, [r3]
vldr s14, [r7, #16]
vcmpe.f32 s14, s15
vmrs APSR_nzcv, fpscr
bgt.n 0x80022c6 <Controller_Config_MapInputJoystickAsJoystick+230>
ldr r3, [r7, #24]
vldr s15, [r3]
vneg.f32 s15, s15
vldr s14, [r7, #16]
vcmpe.f32 s14, s15
vmrs APSR_nzcv, fpscr
bpl.n 0x8002302 <Controller_Config_MapInputJoystickAsJoystick+290>
In the assembly above, the microcontroller HardFaults on the instr, vldr s15, [r3]
at which point, the s15
register is 1.00000238
and the r3
register is 0x802007d
(This is the address of the float *deadzone_x
).
I am concerned as to why this might be failing? I would love to use this function using a float *
without casting a new float
variable of a pointer. The instruction difference is considerable and would save a lot of processing time.
I don't know whether this is a general C programming misconception or perhaps something to do with the compiled ARM assembly? Any help would be appreciated.
I can provide you with any data, views or whatever might help. Thanks.
Edit 1:
This is workaround I am using, not much difference. I just dereference the pointer. You hate to C it.
/*
* Input Configuration Buffer:
* Byte 0:
* Bit 0: Input Joystick Left (0) or Input Joystick Right (1)
* Bit 1: Invert X-Axis (1)
* Bit 2: Invert Y-Axis (1)
* Bit 3: Output Joystick Left (0) or Output Joystick Right (1)
* Bits 4-7: Don't Care
* Byte 1: X-Deadzone 4th-Byte (float)
* Byte 2: X-Deadzone 3rd-Byte (float)
* Byte 3: X-Deadzone 2nd-Byte (float)
* Byte 4: X-Deadzone 1st-Byte (float)
* Byte 5: Y-Deadzone 4th-Byte (float)
* Byte 6: Y-Deadzone 3rd-Byte (float)
* Byte 7: Y-Deadzone 2nd-Byte (float)
* Byte 8: Y-Deadzone 1st-Byte (float)
*/
void Controller_Config_MapInputJoystickAsJoystick(Controller_HandleTypeDef *c, uint8_t *ic_buffer){
uint8_t js_in = GET_BIT(ic_buffer[0], 0);
uint8_t invert_x = GET_BIT(ic_buffer[0], 1);
uint8_t invert_y = GET_BIT(ic_buffer[0], 2);
uint8_t js_out = GET_BIT(ic_buffer[0], 3);
float deadzone_x = (float)(*(float *)(&ic_buffer[1]));
float deadzone_y = (float)(*(float *)(&ic_buffer[5]));
float val_x = invert_x ? -joysticks[js_in].x.val : joysticks[js_in].x.val;
float val_y = invert_y ? -joysticks[js_in].y.val : joysticks[js_in].y.val;
if((val_x > deadzone_x) || (val_x < -deadzone_x)){
c->joysticks._bits[js_out*2 + 0] += (int16_t)(val_x * -INT16_MIN);
}
if((val_y > deadzone_y) || (val_y < -deadzone_y)){
c->joysticks._bits[js_out*2 + 1] += (int16_t)(val_y * -INT16_MIN);
}
}
Debugger Output of Working Code
Debugger Output of Non-Working Code
Edit 2: