# Fixed point types and sine wave generation

We've found that the variety of data types offered by the compiler is

of paramount importance to the ease and effectiveness of embedded

programming. Having lots of data types makes implementing your

programming solution easier. It also removes a big source of error:

the hand-optimization needed to encode data in assembly programs.

Starting in 2007 we're offering a large variety of fixed point data

types in new releases of our compilers. Fixed point data types handle

fractional values ("Fractional" types) and occasionally types with

fractional and small integer components ("Accumulator" types).

These are the relevant types:

Type | Description |
---|---|

fixed168 | 16 bits integer, 8 bits fraction |

fixed1616 | 16 bits integer, 16 bits fraction |

_Fract | 16 bits fraction |

fract8 | 8 bits fraction |

fract16 | 16 bits fraction |

fract24 | 24 bits fraction |

_Accum | 8 bits integer, 16 bits fraction |

accum88 | 8 bits integer, 8 bits fraction |

accum816 | 8 bits integer, 16 bits fraction |

accum824 | 8 bits integer, 24 bits fraction |

If you're tempted to use floating-point math in your application,

consider fixed-point instead. The processing is substantially easier

and less memory-intensive, and the underlying math is easier to

verify.

When your programming challenge deals with fractional values, you can

describe them naturally and combine them with integers with ease. You

don't have to remember to perform conversions or use translated number

systems: the compiler performs data promotion automatically.

## Catch the wave

One good use of fractional values is in sine wave generation. It helps

to keep the sine wave values as fractional when dealing with a

variable magnitude described as an integer.

There are two ways to generate accurate sine waves: using the

transcendental function and using "rectangle rule integration".

## Sine wave using fixed point transcendentals

Byte Craft Limited offers a fixed point transcendental library

suitable for use with our fixed point data types. It is retargetable:

you can change the underlying data type (just redefine "real" and the

real fixed-point suffix) to the smallest necessary resolution and

recompile.

This is a program that emits a PWM sinewave:

#pragma option f 0; #include <9RS08KA2.h> /* This is a sine wave function generator for RS08. It will generate a PWM function on an output pin suitable to pass through an RC network. It makes use of the two timers on the RS08: the slower 32kHz RTI graphs the sine wave, and the faster MTIM switches the output. This software uses threads to manage the event-driven work of generating the signal. */ //define real accum88 //define matching _rs real suffix to match real, //for use with constants #define real accum88 #define _rs hk #include >FIX_math.h< #define OUTPUT (PORTA.0) /* PWM uses the modulo overflow to change from on duty to off duty. */ _Bool on_duty; unsigned int8 duty; #pragma thread PWM() INTERRUPT (MTIMSC.TOF); void PWM(void) { if(on_duty) { OUTPUT = 1; MTIMMOD = duty; //reset TOF } else { OUTPUT = 0; MTIMMOD = 255 - duty; //reset TOF } on_duty = ~on_duty; } #pragma thread sine_wave() INTERRUPT (SRTISC.RTIF); #define TWOPI (__fix_pi * 2) //put a 1 in the LS fract bit of an accum88 #define MINFRACT ((real)0x0001) unsigned real position; void sine_wave(void) { //update the duty cycle duty = 128 + (int8)(127.0 /* _rs */ * fix_sin(position)); //advance to next position in waveform position = (position + MINFRACT); //loop if (position > TWOPI) position = 0; SRTISC.RTIACK = 1; } void main(void) { on_duty = 0; duty = 128; position = 0.0r; //start the RTI SRTISC.CLKS = 0; //1 kHz oscillator SRTISC.RTIS = 0b001; //8ms period SRTISC.RTIACK = 1; //reset any stray interrupt SRTISC.RTIE = 1; //enable //start the PWM MTIMCLK.CLKS = 0b01; //fixed-frequency clock MTIMCLK.PS = 0; //no prescaling MTIMMOD = duty; //initial reset of TOF MTIMSC.TOIE = 1; //interrupt enable MTIMSC.TSTP = 0; //enable while(1) __DISPATCH(); } #include <FIX_math.c>

## Sine wave using rectangle-rule integration

This is a different method of generating both sine and cosine

waves. It generates less code but does not use radian measurements or

keep its results within the range -1..1.

#pragma option f 0; #include <9RS08KA2.h> /* This is a sine wave function generator for RS08. It will generate a PWM function on an output pin suitable to pass through an RC network. It makes use of the two timers on the RS08: the slower 32kHz RTI graphs the sine wave, and the faster MTIM switches the output. This software uses threads to manage the event-driven work of generating the signal. */ //prototype void __DISPATCH(void); //define real accum88 //define matching _rs real suffix to match real, //for use with constants #define real accum88 #define _rs hk #define OUTPUT (PORTA.0) /* PWM uses the modulo overflow to change from on duty to off duty. */ _Bool on_duty; unsigned int8 duty; #pragma thread PWM() INTERRUPT (MTIMSC.TOF); void PWM(void) { if(on_duty) { OUTPUT = 1; MTIMMOD = duty; //reset TOF } else { OUTPUT = 0; MTIMMOD = 255 - duty; //reset TOF } on_duty = ~on_duty; } #pragma thread sine_wave() INTERRUPT (SRTISC.RTIF); //accumulators for sine and cosine waveforms. real sv, cv; //temporary real temp; //8ms time interval #define t_int (8/1000) void sine_wave(void) { //store sine value before alteration. temp = sv; sv = cv * t_int; cv = temp * t_int; //sv //use the sine value duty = 128 + (int8)(sv); SRTISC.RTIACK = 1; } void main(void) { on_duty = 0; duty = 128; //initialize sv = 127; cv = 0; //start the RTI SRTISC.CLKS = 0; //1 kHz oscillator SRTISC.RTIS = 0b001; //8ms period SRTISC.RTIACK = 1; //reset any stray interrupt SRTISC.RTIE = 1; //enable //start the PWM MTIMCLK.CLKS = 0b01; //fixed-frequency clock MTIMCLK.PS = 0; //no prescaling MTIMMOD = duty; //initial reset of TOF MTIMSC.TOIE = 1; //interrupt enable MTIMSC.TSTP = 0; //enable while(1) __DISPATCH(); }