This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I'm trying to do a multiply and add operation using the hardware multiplier in the MSP430F5418A. I'm using fractional numbers and as overflow is not acceptable I have enabled the saturation mode.
Now when I try to preload the result registers, the register contains the value shifted left by one position. This of course gives me completely wrong results. I have a minimal example here (for CCSv5.1):
#include "msp430x54xA.h"
void main(void)
{
WDTCTL =
WDTPW+WDTHOLD; // Stop WDT
MPY32CTL0 =
MPYSAT | MPYFRAC; // fractional number mode, saturation mode
RESLO = 0;
RESHI =
0x2000; // 0.25
// now readable in RESHI: 0x4000 -> 0.5
MACS =
0x4000; // 0.5 (Load first operand -signed MAC)
OP2 =
0x4000; // 0.5 (Load second operand)
// now readable in RESHI: 0x6000 -> 0.75 instead of
0x4000 -> 0.5
__bis_SR_register(LPM4_bits); // Enter LPM4
__no_operation();
// For debugger
}
Things get even worse if you try preloading with 0.5:
#include "msp430x54xA.h"
void main(void)
{
WDTCTL =
WDTPW+WDTHOLD; // Stop WDT
MPY32CTL0 =
MPYSAT | MPYFRAC; // fractional number mode, saturation mode
RESLO = 0;
RESHI =
0x4000; // 0.5
// now readable in RESHI: 0x8000 -> -1
MACS =
0x4000; // 0.5 (Load first operand -signed MAC)
// now readable in RESHI: 0x7FFF -> nearly 1
OP2 =
0x4000; // 0.5 (Load second operand)
// now readable in RESHI: 0x7FFF -> nearly 1 instead
of 0x6000 -> 0.75 or at least -0.25
__bis_SR_register(LPM4_bits); // Enter LPM4
__no_operation();
// For debugger
}
Does anyone have an idea why this happens? I think it maybe caused by the multiplier changing the values if you read out a fractional value, so it changes it when a fractional value is written as well, but I don't know. This also happens if I preload the register and then switch on saturation and fractional mode, so no easy workaround. Preshifting the values involves the loss of the LSB, so not really an option.
Okay so I tried some things today, and can say it's not related to the saturation mode. Switching on the fractional mode on alone leads to this behavior.
There is this part in the description of the multiplier:
The fractional mode is enabled with MPYFRAC = 1 in register MPY32CTL0. The actual content of the
result register(s) is not modified when MPYFRAC = 1. When the result is accessed using software, the
value is left shifted one bit, resulting in the final Q formatted result. This allows user software to switch
between reading both the shifted (fractional) and the unshifted result. The fractional mode should only be
enabled when required and disabled after use.
So am I right when guessing, that the Q15 number is actually stored in RESHI.14-RESHI.0 and RESLO.15, and if I read it out the result is shifted to RESHI.15-RESHI.0 ?
And if I wanted to preload it I'd have to make sure, that I do the sign extension to RES2 and RES3 as well as storing my fractional number in RESHI.14-RESLO.15 instead of just writing it to RESHI?
I'm not sure how many cycles it takes to add two signed numbers, but all the steps I have to take to preload the multiplier correctly for a fractional MACS operation sound to be more than that.
Just in case someone else will stuble upon this, I haven't found an easy solution for using the MPY32 for this, so I've created a workaround:
typedef signed int sFix0_15; // -1 .. 0.999969482421875
| resolution: 1/32768 = 3.0517578125E-5
/*
* sFix0_15
macc0_15(sFix0_15 a, sFix0_15 b, sFix0_15 plus)
*
* Multiplies
two Q0.15 numbers and adds the result to a third
*
* Simulates
the saturation behavior, but -1 * -1 + -1 ~= -3e-5
*
*
@parameters:
* sFix0_15 a - factor 1
* sFix0_15 b - factor 2
* sFix0_15 plus - summand
*
* @returns:
* sFix0_15 m = a * b +
plus
*/
sFix0_15 macc0_15(sFix0_15 a, sFix0_15 b, sFix0_15 plus)
{
MPYS = a;
OP2 = b;
sFix0_15 result = RESHI
+ plus;
volatile int SR = _get_SR_register();
if
((SR & V))
{
if (SR & N)
{
return 0x7FFF;
}
else
{
return 0x8000;
}
}
return result;
}
**Attention** This is a public forum