I have some code on an embedded system (the
There seems to me to be 2 more bytes that can contain data, given that I declared it as a long.
Please let me know if more information is needed to solve this issue, or if there is a glaringly obvious solution to this issue.
My full code, in case it helps. Much of the main code is merely initializing the MCU, and the problem code itself is located at one of the flags near the bottom of the code. I have left the initializers in case they help.
#include <msp430.h>
#include <stdio.h>
#include <stdlib.h>
#define PWM_16HZ 2048
#define PWM_32HZ 1024
char printkeeper;
int memval3_old = 0, memval4_old = 0, memval3_new = 0, memval4_new = 0, i = 0; //Old is for storing old ADC values
int voltage_difference_new, voltage_difference_old, voltage_difference_range, voltage_difference_doppler; //Remove float whenever possible!
long int range_um, speed_um;
int range, speed;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
// GPIO Setup
P1OUT &= ~BIT0; // 16Hz Clock Pin Setup
P1DIR |= BIT0 | BIT1 | BIT2 | BIT5; // Bits 1.2, 1.5 set to clock (TA1.1, TB0.2) (p88_s, p91_s)
P1SEL0 |= BIT0 | BIT1 | BIT2 | BIT5; // See p88-90_s
PJSEL0 = BIT4 | BIT5; // For XT1 Oscillator (p118_s)
P1SEL1 |= BIT3 | BIT4 ; // ADC Pin Setup
P1SEL0 |= BIT3 | BIT4 ; // 1.3 and 1.4 set to ADC input (A3, A4) from p90_s
P3DIR |= BIT0; // Set Pin 3.0 as output, for permanent 3.3V.
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
//P1OUT |= BIT0;
// Clock System Setup
CSCTL0_H = CSKEY_H; // Unlock CS registers
CSCTL1 = DCOFSEL_3; // Set DCO to 4MHz (p105)
CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK; // Set clock source
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers, clock speed 1MHz
CSCTL4 &= ~LFXTOFF; // Something related to the 32kHz oscillator
do
{
CSCTL5 &= ~LFXTOFFG; // Clear XT1 fault flag
SFRIFG1 &= ~OFIFG;
} while (SFRIFG1 & OFIFG); // Test oscillator fault flag
CSCTL0_H = 0; // Lock clock registers
//ADC Setup
ADC12CTL0 = ADC12SHT0_0 | ADC12ON; // Sampling time, S&H=4, ADC12 on [p893, CTL0 = control 0, SHT0_0 = sample & hold time, knowledge of register value from p88_s]
ADC12CTL1 = ADC12SHP | ADC12SHS_4 | ADC12CONSEQ_1; // Use TA1.1 to trigger, (SHP means using sample timer (p897), SHS means "sample-and-hold source select" (p895, p84_s)
// which selects which source is used to activate sampling (4 being TA1.1 because of p84_s), CONSEQ_1 = Conversion sequence select,
// 1 means multiple-channel which means multiple channels are converted and sampled, memory gets overriden everytime (p881)
ADC12CTL2 |= ADC12RES_2; // 12-bit conversion results, p897
ADC12CTL3 |= ADC12CSTARTADD_3; // Use MEM3/MCTL3 as first, p898
ADC12MCTL3 = ADC12INCH_3 ; // A3 ADC input select from Input Channel 3 (p901), output to MEM3
ADC12MCTL4 = ADC12INCH_4 | ADC12EOS; // A4 ADC input select, also setting EOS bit at A4
ADC12IER0 |= ADC12IE3 | ADC12IE4; // Enable ADC interrupt [IER = interrupt enable, for IFG0 bit, which tells us when the sequence is complete]
// Configure TimerA1.1 to periodically trigger ADC12 at a rate of 32Hz
TA1CCR0 = PWM_32HZ - 1; // PWM Period for TA1, 1024/32768 = /32
TA1CCTL1 = OUTMOD_3; // TACCR1 set/reset (Shape of set/reset in p652)
TA1CCR1 = PWM_32HZ / 2; // TACCR1 PWM Duty Cycle
TA1CTL = TASSEL__ACLK | MC__UP; // ACLK, up mode
// Configure TimerA0.0 to generate a 16Hz Square Wave
TB0CCR0 = PWM_16HZ - 1; // PWM Period for TB0, 2048/32768 = /16
TB0CCTL2 = OUTMOD_7; // TBCCR1 set/reset (Shape of set/reset in p652)
TB0CCR2 = PWM_16HZ /2; // TB0CCR2 PWM Duty Cycle
TB0CTL = TASSEL__ACLK | MC__UP; // ACLK, up mode
ADC12CTL0 |= ADC12ENC | ADC12SC; // Start sampling/conversion
printf("135\n");
__bis_SR_register(LPM0_bits | GIE); // Enter LPM0, enable interrupts
__no_operation();
}
// ADC12 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_B_VECTOR
__interrupt void ADC12ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_B_VECTOR))) ADC12ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV, ADC12IV__ADC12RDYIFG))
{
case ADC12IV__ADC12IFG3: // Vector 18: ADC12MEM3
memval3_old = memval3_new;
memval3_new = ADC12MEM3;
ADC12IFGR0 &= ~ADC12IFG3;
break;
case ADC12IV__ADC12IFG4: // Vector 20: ADC12MEM4
memval4_old = memval4_new;
memval4_new = ADC12MEM4;
voltage_difference_new = abs((memval3_new - memval4_new)); // These values are both ve, rising edge
voltage_difference_old = abs((memval3_old - memval4_old)); // These values are both ve, falling edge
voltage_difference_range = ((voltage_difference_new voltage_difference_old));
voltage_difference_doppler = ((voltage_difference_new - voltage_difference_old)); //Lower frequency means moving away
//printf("%d\n", voltage_difference_range);
voltage_difference_range = 80;
range_um = voltage_difference_range * 1159; //Check notebook math, this is in micrometers to avoid floats
speed_um = voltage_difference_doppler * 15766; //Check notebook math, also in micrometers
if (printkeeper == 31){
printkeeper = 0;
printf("VD: %d\n", voltage_difference_range);
printf("R: %d\n", range_um);
i ;
}
else {
printkeeper = printkeeper 1;
}
ADC12MCTL4 |= ADC12EOS;
ADC12CTL0 &= ~ADC12ENC;
ADC12CTL0 |= ADC12ENC;
break;
default: break;
}
}
CodePudding user response:
The overflow occurs before the assignment. Expressions have type and voltage_difference_range * 1159
is an int
type expression.
So the overflow occurs and the result is assigned to the long
, where an implicit conversion occurs after the overflow.
With respect to expression types: int * int == int
, but int * long == long
, so using a literal integer of type long
will cause the expression to have type long
:
int voltage_difference_range = 80 ;
long range_um = voltage_difference_range * 1159L;
In cases where the operands are variables rather then literals you would need a cast of at least one operand if they were both int
- e.g.:
int a = 80 ;
int b = 1159 ;
long x = (long)a * b;
CodePudding user response:
range_um = voltage_difference_range * 1159;
first performs the multiplication, then it assigns the result to range_um
.
The operands of the multiplication are both int
, voltage_difference_range
and 1159
. Multiplication of int
by int
is performed in int
arithmetic, producing an int
result. Since int
is 16 bits in your C implementation, multiplying 80 by 1159 overflows the type, and then the behavior is not defined by the C standard.
It appears you are indeed experiencing a wrapping modulo 65,536 in this case, so that the result produced is 27,184 instead of 92,720. Then this result is assigned to range_um
. The assignment converts the right operand to the type of the left, so 27,184 is converted to lnog int
and stored in range_um
. The fact that range_um
is long int
has no effect on the prior multiplication.
To perform multiplication with long int
, change or convert one (or both) of the operands to long int
, as in range_um = voltage_difference_range * 1159L;
.