Fast lookup plus interpolation computation of non-linear functions
// Fast integer arithmetic lookup+interpolation method for converting
// barometric pressure readings to altitude readings.
// Each Lookup Table (LUT) entry is the altitude in centimeters above
// sea level, corresponding to an implicit pressure value,
// calculated as [PA_INIT - 1024*LUTindex] in Pascals.
// The region of interest is approximately 460metres below sea level,
// to 10000 metres above sea level.
typedef signed long s32;
#define PZLUT_ENTRIES 80
#define PA_INIT 106956L
#define PA_DELTA 1024L
#define Z_LIMIT_LO -99999L
#define Z_LIMIT_HI 99999L
const s32 gPZTbl[PZLUT_ENTRIES] = {
-45853,
-37662,
-29407,
-21087,
-12700,
-4245,
4279,
12874,
21540,
30279,
... // values removed for brevity
959708,
984147,
1009345
};
// Calculates the altitude in centimeters above sea level, given the barometric
// sensor pressure reading in pascals. The nearest lower LUT index is computed.
// The altitude is then linearly interpolated from the corresponding altitude
// values at the lower and next higher LUT index. Computation is optimized by
// ensuring the difference between LUT entries are spaced by a power of 2, in
// this case 2^10 (1024), so no integer division is required.
// Returns the error values Z_LIMIT_LO or Z_LIMIT_HI if
// the pressure data exceeds the LUT index limits.
s32 sns_Pa2Cm(s32 pa) {
s32 inx,pa1,z1,z2,z;
if (pa > PA_INIT) {
z = Z_LIMIT_LO;
}
else {
inx = (PA_INIT - pa)>>10;
if (inx >= PZLUT_ENTRIES-1) {
z = Z_LIMIT_HI;
}
else {
pa1 = PA_INIT - (inx<<10);
z1 = gPZTbl[inx];
z2 = gPZTbl[inx+1];
z = z1 + (((pa1-pa)*(z2-z1))>>10);
}
}
return z;
}
Simple Bit Manipulation Macros
/* Basic bit manipulation macros
No one should ever have to rewrite these
*/
//Set bit y (0-indexed) of x to '1' by generating a a mask with a '1' in the proper bit location and ORing x with the mask.
#define SET(x,y) x |= (1 << y)
//Set bit y (0-indexed) of x to '0' by generating a mask with a '0' in the y position and 1's elsewhere then ANDing the mask with x.
#define CLEAR(x,y) x &= ~(1<< y)
//Return '1' if the bit value at position y within x is '1' and '0' if it's 0 by ANDing x with a bit mask where the bit in y's position is '1' and '0' elsewhere and comparing it to all 0's. Returns '1' in least significant bit position if the value of the bit is '1', '0' if it was '0'.
#define READ(x,y) ((0u == (x & (1<<y)))?0u:1u)
//Toggle bit y (0-index) of x to the inverse: '0' becomes '1', '1' becomes '0' by XORing x with a bitmask where the bit in position y is '1' and all others are '0'.
#define TOGGLE(x,y) (x ^= (1<<y))
SR-87 GPS Module
#use rs232(baud=4800,xmit=PIN_C6,rcv=PIN_C7,bits=8,stop=1,parity=n,stream=GPS,force_sw)
#include<string.h>
#include<stdlib.h>
//char latitude[17],longitude[17],buffer[17];
// Read the lattitude and longitude
void get_position()
{
int8 rx_count,rx_buffer;
rx_count=0;
strcpy(buffer,"GPRMC");
do
{
rx_count=0;
output_low(PIN_A5);
while(fgetc(GPS) !='$');
while((rx_buffer=fgetc(GPS))!=',')
{
latitude[rx_count]=rx_buffer;
rx_count++;
}
latitude[rx_count]='\0';
}while(strcmp(latitude,buffer));
//*****************************************************************
while(getc(GPS)!=',');
while(getc(GPS)!=',');
rx_count=0;
do
{
rx_buffer=fgetc(GPS);
latitude[rx_count]=rx_buffer;
rx_count++;
}while(rx_buffer!=',');
latitude[rx_count]=fgetc(GPS);
rx_count++;
latitude[rx_count]='\0';
rx_buffer=fgetc(GPS);
rx_count=0;
do
{
rx_buffer=fgetc(GPS);
longitude[rx_count]=rx_buffer;
rx_count++;
}while(rx_buffer!=',');
longitude[rx_count]=fgetc(GPS);
rx_count++;
longitude[rx_count]='\0';
}
//wait untill a valid data
void get_fix()
{
int8 rx_count,rx_buffer;
rx_count=0;
strcpy(buffer,"GPRMC");
do
{
do
{
rx_count=0;
while(fgetc(GPS) !='$');
while((rx_buffer=fgetc(GPS))!=',')
{
latitude[rx_count]=rx_buffer;
rx_count++;
}
latitude[rx_count]='\0';
}while(strcmp(latitude,buffer));
while(fgetc(GPS) !=',');
rx_buffer=fgetc(GPS);
}while(rx_buffer !='A');
}
Olympic Averaging
int16 adcval,sum,max,min;
int8 i;
#define samples 10
max=0;
min=0xFFFF; //Set max and min to the limits of the range.
for (i=0;i<samples;i++){
adcval=read_adc();
if (adcval>max) max=adcval; //Update max and min on the fly.
if (adcval<min) min=adcval;
sum+=adcval; //Generate sum of all samples.
}
sum-=max; //Remove the maximum, and minimum values
sum-=min; //as likely outliers.
return(sum/(samples-2)); //Average the remaining total.
//If samples = 10 then the division becomes sum<<3
Finite State Machine Template
/*********************************************************************
Finiste State Machine design example
FSM based embedded software design has several advantages:
1. You can translate the systems' requirements into FSM diagramas or
state transition tables.
2. From the FSM diagram or state transition table you can validate if the design
is right or wrong before actually start coding.
3. It makes the code easier to understand
4. You can have traceability from the requirements document to the
code
5. Determinism; you can now exactly what the system is doing at any time
6. Hmmm I don't know, they just look good in C!
In this code Example it is shown how to implement the following FSM
state transition table into C code. You can use this as a template by
replacing inputs and outputs sets, set of states by your actual application
values.
I hope this helps.
Current State INPUT_0 INPUT_1 INPUT_2 INPUT_3 Next State OUTPUT_0
DETECT_IN0 0 X X X DETECT_IN1 0
1 X X X DETECT_IN0 0
DETECT_IN1 X 0 X X DETECT_IN2 0
X 1 X X DETECT_IN1 0
DETECT_IN2 X X 0 X DETECT_IN3 0
X X 1 X DETECT_IN2 0
DETECT_IN3 X X X 0 SET_OUTPUT 0
X X X 1 DETECT_IN3 0
SET_OUTPUT X X X X DETECT_IN0 1
X X X X DETECT_IN0 1
*
********************************************************************/
#include <stdio.h>
/*Inputs and outputs sets
You can give meaningful names to the IO ports of your microcontroller,
and that will make the code easier to understand and make it consistent
with a FSM diagram or state transition table
*/
#define INPUT_0 PTA0
#define INPUT_1 PTA1
#define INPUT_2 PTA2
#define INPUT_3 PTA3
#define OUTPUT_0 PTB0
/*
The inputs have pull-ups resistors so we can define a condition
to identify when an input has been selected, in this case an
input is selected when its value is 0
*/
#define SELECTED 0x00
/*Set of states
It is more convenient to give meaningful names to the states
and it's better when you can map them to a finite state machine
diagram or state transition table.
*/
typedef enum { DETECT_IN0 = 0x00,
DETECT_IN1,
DETECT_IN2,
DETECT_IN3,
SET_OUTPUT} SM_STATES;
/*We need a state variable to store the next state value as well
and we have to assign an initial state to it
*/
unsigned char state = DETECT_IN0;
int ctr_ms = 500; /*This finite state machine executes every 500 ms*/
/*wait function*/
static unsigned char wait_ms(void);
void main(void) {
for(;;) {
if(wait_ms()) { /*The state machine is synch to a timer*/
switch(state) {
case DETECT_IN0:
OUTPUT_0 = 0;
if(INPUT_0 == SELECTED) {
state = DETECT_IN1;
}
break;
case DETECT_IN1:
if(INPUT_1 == SELECTED) {
state = DETECT_IN2;
}
break;
case DETECT_IN2:
if(INPUT_2 == SELECTED) {
state = DETECT_IN3;
}
break;
case DETECT_IN3:
if(INPUT_3 == SELECTED) {
state = SET_OUTPUT;
}
break;
case SET_OUTPUT:
OUTPUT_0 = 1;
state = DETECT_IN0;
break;
default:
/*None of the above*/
break;
}
}
} /* loop forever */
/* please make sure that you never leave main */
}
unsigned char wait_ms(void) {
unsigned char ctr_flag;
ctr_flag = 0;
/*Test for timer overflow flag*/
if(TPM_Get_OVFlag() == 1) {
if (ctr_ms == 0) {
ctr_flag = 1;
} else {
ctr_ms--;
}
TPM_Clr_OVFlag();
}
return ctr_flag;
}
Graphics in source code
// This enum defines the value of each of the 256 possible combinations of
// underlines and Os in 8 bits.
enum
{
________,_______O,______O_,______OO,_____O__,_____O_O,_____OO_,_____OOO,
____O___,____O__O,____O_O_,____O_OO,____OO__,____OO_O,____OOO_,____OOOO,
___O____,___O___O,___O__O_,___O__OO,___O_O__,___O_O_O,___O_OO_,___O_OOO,
___OO___,___OO__O,___OO_O_,___OO_OO,___OOO__,___OOO_O,___OOOO_,___OOOOO,
__O_____,__O____O,__O___O_,__O___OO,__O__O__,__O__O_O,__O__OO_,__O__OOO,
__O_O___,__O_O__O,__O_O_O_,__O_O_OO,__O_OO__,__O_OO_O,__O_OOO_,__O_OOOO,
__OO____,__OO___O,__OO__O_,__OO__OO,__OO_O__,__OO_O_O,__OO_OO_,__OO_OOO,
__OOO___,__OOO__O,__OOO_O_,__OOO_OO,__OOOO__,__OOOO_O,__OOOOO_,__OOOOOO,
_O______,_O_____O,_O____O_,_O____OO,_O___O__,_O___O_O,_O___OO_,_O___OOO,
_O__O___,_O__O__O,_O__O_O_,_O__O_OO,_O__OO__,_O__OO_O,_O__OOO_,_O__OOOO,
_O_O____,_O_O___O,_O_O__O_,_O_O__OO,_O_O_O__,_O_O_O_O,_O_O_OO_,_O_O_OOO,
_O_OO___,_O_OO__O,_O_OO_O_,_O_OO_OO,_O_OOO__,_O_OOO_O,_O_OOOO_,_O_OOOOO,
_OO_____,_OO____O,_OO___O_,_OO___OO,_OO__O__,_OO__O_O,_OO__OO_,_OO__OOO,
_OO_O___,_OO_O__O,_OO_O_O_,_OO_O_OO,_OO_OO__,_OO_OO_O,_OO_OOO_,_OO_OOOO,
_OOO____,_OOO___O,_OOO__O_,_OOO__OO,_OOO_O__,_OOO_O_O,_OOO_OO_,_OOO_OOO,
_OOOO___,_OOOO__O,_OOOO_O_,_OOOO_OO,_OOOOO__,_OOOOO_O,_OOOOOO_,_OOOOOOO,
O_______,O______O,O_____O_,O_____OO,O____O__,O____O_O,O____OO_,O____OOO,
O___O___,O___O__O,O___O_O_,O___O_OO,O___OO__,O___OO_O,O___OOO_,O___OOOO,
O__O____,O__O___O,O__O__O_,O__O__OO,O__O_O__,O__O_O_O,O__O_OO_,O__O_OOO,
O__OO___,O__OO__O,O__OO_O_,O__OO_OO,O__OOO__,O__OOO_O,O__OOOO_,O__OOOOO,
O_O_____,O_O____O,O_O___O_,O_O___OO,O_O__O__,O_O__O_O,O_O__OO_,O_O__OOO,
O_O_O___,O_O_O__O,O_O_O_O_,O_O_O_OO,O_O_OO__,O_O_OO_O,O_O_OOO_,O_O_OOOO,
O_OO____,O_OO___O,O_OO__O_,O_OO__OO,O_OO_O__,O_OO_O_O,O_OO_OO_,O_OO_OOO,
O_OOO___,O_OOO__O,O_OOO_O_,O_OOO_OO,O_OOOO__,O_OOOO_O,O_OOOOO_,O_OOOOOO,
OO______,OO_____O,OO____O_,OO____OO,OO___O__,OO___O_O,OO___OO_,OO___OOO,
OO__O___,OO__O__O,OO__O_O_,OO__O_OO,OO__OO__,OO__OO_O,OO__OOO_,OO__OOOO,
OO_O____,OO_O___O,OO_O__O_,OO_O__OO,OO_O_O__,OO_O_O_O,OO_O_OO_,OO_O_OOO,
OO_OO___,OO_OO__O,OO_OO_O_,OO_OO_OO,OO_OOO__,OO_OOO_O,OO_OOOO_,OO_OOOOO,
OOO_____,OOO____O,OOO___O_,OOO___OO,OOO__O__,OOO__O_O,OOO__OO_,OOO__OOO,
OOO_O___,OOO_O__O,OOO_O_O_,OOO_O_OO,OOO_OO__,OOO_OO_O,OOO_OOO_,OOO_OOOO,
OOOO____,OOOO___O,OOOO__O_,OOOO__OO,OOOO_O__,OOOO_O_O,OOOO_OO_,OOOO_OOO,
OOOOO___,OOOOO__O,OOOOO_O_,OOOOO_OO,OOOOOO__,OOOOOO_O,OOOOOOO_,OOOOOOOO,
};
// These macros use the above enum to build the image in a source file.
#define G8(n0) (n0) //!< Build a byte image line
#define G16(n1, n0) (((n1) << 8) | (n0))
//!< Build a halfword image line
#define G32(n3, n2, n1, n0) \
((G16 ((n3), (n2)) << 16) | G16 ((n1), (n0)))
//!< Build a word image line
#define G64(n7, n6, n5, n4, n3, n2, n1, n0) \
((G32 ((n7), (n6), (n5), (n4)) << 32) | G32 ((n3), (n2), (n1), (n0)))
//!< Build a long image line
=====
Example using the letter A in Arial Black 21 font:
Old code:
{
19, // A
0x00040000, 0x00078000, 0x0007F000, 0x0007FC00,
0x0007FF80, 0x0003FFF0, 0x0000FFFC, 0x0000FFFE,
0x0000F1FE, 0x0000F03E, 0x0000F1FE, 0x0000FFFE,
0x0000FFFC, 0x0003FFF0, 0x0007FF80, 0x0007FC00,
0x0007F000, 0x00078000, 0x00040000
};
New code:
{
19, // A
G32 (________,_____O__,________,________),
G32 (________,_____OOO,O_______,________),
G32 (________,_____OOO,OOOO____,________),
G32 (________,_____OOO,OOOOOO__,________),
G32 (________,_____OOO,OOOOOOOO,O_______),
G32 (________,______OO,OOOOOOOO,OOOO____),
G32 (________,________,OOOOOOOO,OOOOOO__),
G32 (________,________,OOOOOOOO,OOOOOOO_),
G32 (________,________,OOOO___O,OOOOOOO_),
G32 (________,________,OOOO____,__OOOOO_),
G32 (________,________,OOOO___O,OOOOOOO_),
G32 (________,________,OOOOOOOO,OOOOOOO_),
G32 (________,________,OOOOOOOO,OOOOOO__),
G32 (________,______OO,OOOOOOOO,OOOO____),
G32 (________,_____OOO,OOOOOOOO,O_______),
G32 (________,_____OOO,OOOOOO__,________),
G32 (________,_____OOO,OOOO____,________),
G32 (________,_____OOO,O_______,________),
G32 (________,_____O__,________,________),
};
Little Endian Converter Functions
unsigned short u16ToLittleEndian( unsigned short u16input )
{/* Use this function to convert a 16-bit number into little endian. */
return( (u16input >> 8) ^ (u16input << 8) );
}// end u16ToLittleEndian()
unsigned long u32ToLittleEndian( unsigned long u32input )
{/* Use this function to convert a 32-bit number into little endian. */
return( (u32input >> 24)
^ ( (u32input >> 8) & 0x000FF00 )
^ ( (u32input << 8) & 0x00FF0000 )
^ ( (u32input << 24) & 0xFF000000 )
);
}// end u32ToLittleEndian()
Universal InfraRed remote pass-thru
#define MAX_IR_INDEX 64
#define ESCAPE_COUNT 0x2200ul /* Could be reduced?*/
#pragma udata ircounts
unsigned int lcounts[MAX_IR_INDEX];
unsigned int hcounts[MAX_IR_INDEX];
#pragma interrupt high_isr /*=section(".tmpdata")*/
void high_isr(void) {
unsigned int l;
unsigned int c;
unsigned char th, tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
// Check that this is the INT0 interrupt
// IRRX is int0
if(INTCONbits.INT0IF)
{
// Disable the interrupt source
INTCONbits.INT0IE = 0;
// the code in the while needs to be balanced so that the ==0 and ==1 bits are the size number of cycles.
while(lindex < MAX_IR_INDEX)
{
while(PORTBbits.RB0 == 0)
{
l++;
if(l == ESCAPE_COUNT)
{
lcounts[lindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; // << 8 ;// Always read L before H
lcounts[lindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always right H before L
TMR1L = 0;
while(PORTBbits.RB0 == 1)
{
l++;
if(l == ESCAPE_COUNT)
{
hcounts[hindex] = 0xffff;
goto done;
}
}
tl = TMR1L;
th = TMR1H; //<< 8 ;// Always read L before H
hcounts[hindex++] = th * 256 + tl;
l = 0;
TMR1H = 0; // Always write H before L
TMR1L = 0;
}
}
done:
codeReady = 1;
// reset interrupt status bit
//INTCONbits.INT0IE = 1;
//INTCONbits.INT0IF = 0;
return;
}
void zeroIR() {
unsigned char c;
// Initialize the IR Count holders
lindex = 0;
hindex = 0;
for(c = 0; c < MAX_IR_INDEX; c++)
{
lcounts[c] = 0xdead;
}
codeReady = 0;
// reset interrupt status bit
INTCONbits.INT0IE = 1;
INTCONbits.INT0IF = 0;
}
void transmitIR(void) {
unsigned char c;
// First check that the code is valid by examining the first LCOUNT
// if it is less than our defined threshold we will not transmit it.
// The first lcount holds the low-going preamble, it must be a minimum length or it does not
// represent a valid IR Transmission preamble.
if(lcounts[0] < PREAMBLE_MINIMUM)
{
return;
}
sprintf(serTX, (CAST) "$%c%cIC%d,", id1, id2, lindex);
rs485_puts(serTX);
for(c = 0; c < lindex; c++)
{
sprintf(serTX, (CAST) "%04x,%04x, ", lcounts[c], hcounts[c]);
rs485_puts(serTX);
}
sprintf(serTX, (CAST) "\n");
rs485_puts(serTX);
}
Integer to ASCII
/***** integerToAscii.h *****/
#define BASE_OCTAL 8
#define BASE_DECIMAL 10
#define BASE_HEXADECIMAL 16
#define BUFFER_SIZE 32
char* integerToASCII(long int value, int base);
/***** integerToAscii.c *****/
char* integerToASCII(long int value, int base){
int aux;
static char buf[BUFFER_SIZE] = {0};
int isNeg=0;
if (value == 0) {
buf[0]='0';
return &buf[0];
}
if (value<0) {
isNeg = 1;
value *= -1;
}
for(aux=BUFFER_SIZE; value && aux ; --aux, value /= base){
buf[aux] = "0123456789abcdef"[value % base];
}
if (isNeg) {
buf[aux] = '-';
return &buf[aux];
}
return &buf[aux+1];
}
GPIO library
//---------------------------------------------------------
// start of header file (gpio.h)
//---------------------------------------------------------
#if !defined(_GPIO_H_)
#define _GPIO_H_
typedef unsigned long dword;
typedef struct tGPIOpinTag
{
dword dwReg;
dword dwClr;
dword dwSet;
int iBit;
dword dwFunction;
} tGPIOpin;
#define REG32 volatile dword *
//
// bit patterns for alternate pin functions.
//
#define PINFUNC_GPIO ( 0x00000000 )
#define PINFUNC_ALT1 ( 0x55555555 )
#define PINFUNC_ALT2 ( 0xAAAAAAAA )
#define PINFUNC_ALT3 ( 0xFFFFFFFF )
//
// Active high and low works by swapping the SET and CLR register offsets round
//
#define GPIO_ACTIVE_L FIO_SET_OFS, FIO_CLR_OFS
#define GPIO_ACTIVE_H FIO_CLR_OFS, FIO_SET_OFS
//
// Start addresses of GPIO blocks of registers
//
#define LPC_GPIO_BASE ( 0x2009C000UL )
#define LPC_GPIO0_BASE ( LPC_GPIO_BASE + 0x00000 )
#define LPC_GPIO1_BASE ( LPC_GPIO_BASE + 0x00020 )
#define LPC_GPIO2_BASE ( LPC_GPIO_BASE + 0x00040 )
#define LPC_GPIO3_BASE ( LPC_GPIO_BASE + 0x00060 )
#define LPC_GPIO4_BASE ( LPC_GPIO_BASE + 0x00080 )
//
// Offsets to the direction register and PIN register
//
#define FIO_SET_OFS ( 0x00000018 )
#define FIO_CLR_OFS ( 0x0000001C )
#define FIO_DIR_OFS ( 0x00000000 )
#define FIO_PIN_OFS ( 0x00000014 )
#define FIO_MASK_OFS ( 0x00000010 )
// Parameters for vGPIODDsetDirection
#define PIN_IN ( FALSE )
#define PIN_OUT ( TRUE )
//
// Macro for pin definition structure
//
#ifdef _INSIDE_GPIODD_
//
// this version is for use inside the gpio module
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
const tGPIOpin t##name = { \
LPC_GPIO##port##_BASE, \
GPIO_ACTIVE_##act, \
bit, \
PINFUNC_##func \
}; \
const tGPIOpin * const name = &t##name;
#else
//
// and this is how external modules see the pin definition
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
extern const tGPIOpin * const name;
#endif
//
// include the hardware pin allocations from another file
// (see example below)
//
#include "gpio_pindefs.h"
extern void vGPIODDsetPinFunction( const tGPIOpin * const psPin );
extern void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDsetActive( const tGPIOpin * const psPin );
extern void vGPIODDsetInactive( const tGPIOpin * const psPin );
extern bool boGPIODDgetPin( const tGPIOpin * const psPin );
#endif // _GPIO_H_
//---------------------------------------------------------
// end of header file (gpio.h)
//---------------------------------------------------------
//---------------------------------------------------------
// start of example gpio_pindefs.h
//---------------------------------------------------------
#if !defined(_GPIO_PINDEFS_H_)
#define _GPIO_PINDEFS_H_
// LEDs
PINFUNC_DEF( GPIO_LED_GREEN, 1, 25, L, GPIO )
// USB interface
PINFUNC_DEF( GPIO_USB_VBUS, 1, 30, H, ALT1 )
PINFUNC_DEF( GPIO_USB_CONNECT, 2, 9, L, ALT1 )
// Serial Ports
PINFUNC_DEF( UART0_RX, 0, 3, H, ALT1 )
PINFUNC_DEF( UART0_TX, 0, 2, H, ALT1 )
PINFUNC_DEF( UART1_RX, 0, 16, H, ALT1 )
PINFUNC_DEF( UART1_TX, 0, 15, H, ALT1 )
// SPI port
PINFUNC_DEF( SPI_MOSI, 0, 9, H, ALT2 )
PINFUNC_DEF( SPI_MISO, 0, 8, H, ALT2 )
PINFUNC_DEF( SPI_SCK, 0, 7, H, ALT2 )
PINFUNC_DEF( SPI_SSEL, 0, 6, L, ALT2 )
#endif // _GPIO_PINDEFS_H_
//---------------------------------------------------------
// end of example gpio_pindefs.h
//---------------------------------------------------------
//---------------------------------------------------------
// start of gpio.c
//---------------------------------------------------------
#define _INSIDE_GPIODD_ ( 1 )
#include "gpio.h"
/* --------------------------------------------------------
vGPIODDsetPinFunction
........................................................
Description : Set the pin connect block from a pin
definition
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinFunction( const tGPIOpin * const psPin )
{
if ( psPin )
{
// Each PINSELXX register contains the settings
// for 16 port pins. Each PINSEL register is 4 bytes
// above the previous one. Base addresses for ports
// are 32 bytes apart.
dword dwPinSel = LPC_PINCON_BASE +
((psPin->dwReg - LPC_GPIO0_BASE) / 4) +
((psPin->iBit / 16) * 4);
dword dwMask = ( 0x00000003 << ( 2 * ( psPin->iBit % 16 ) ) );
REG32 pdwPinSel = (REG32)dwPinSel;
*pdwPinSel = ( *pdwPinSel & ~dwMask ) |
( psPin->dwFunction & dwMask );
}
}
/* --------------------------------------------------------
vGPIODDsetPinDirection
........................................................
Description : Sets the pin direction from a pin
definition
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
if( boOutput )
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) |= ( 1 << psPin->iBit );
}
else
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) &= ~( 1 << psPin->iBit );
}
}
}
/* --------------------------------------------------------
vGPIODDconfigurePin
........................................................
Description : Combination function to configure and set
direction of GPIO pin
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
vGPIODDsetInactive( psPin );
vGPIODDsetPinFunction( psPin );
vGPIODDsetPinDirection( psPin, boOutput );
}
}
/* --------------------------------------------------------
vGPIODDsetActive
........................................................
Description : Sets a pin to its active state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetActive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Set register to set a single bit
(*((REG32) (psPin->dwReg + psPin->dwSet))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
vGPIODDsetInactive
........................................................
Description : Sets a pin to its inactive state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetInactive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Clr register to clear a single bit
(*((REG32) (psPin->dwReg + psPin->dwClr))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
boGPIODDgetPin
........................................................
Description : Gets the current state of a pin
Params : psPin - pin definition
Returns : TRUE if the pin is in its active state,
FALSE otherwise.
----------------------------------------------------- */
bool boGPIODDgetPin( const tGPIOpin * const psPin )
{
if ( psPin )
{
dword dwPins = *((REG32) (psPin->dwReg + FIO_PIN_OFS));
if ( psPin->dwSet > psPin->dwClr )
{
dwPins = ~dwPins;
}
return ((dwPins & ( 1 << psPin->iBit )) != 0 );
}
else
{
return FALSE;
}
}
//---------------------------------------------------------
// end of gpio.c
//---------------------------------------------------------
I2C driver using bit bang
typedef struct
{
unsigned int PIN0:1;
unsigned int PIN1:1;
unsigned int PIN2:1;
unsigned int PIN3:1;
unsigned int PIN4:1;
unsigned int PIN5:1;
unsigned int PIN6:1;
unsigned int PIN7:1;
} PORT;
/* TODO: Example address shown, but the proper address */
#define PORT0 *(volatile PORT *)0x1234
/* Define the port used for I2C data and clk as shown above to access them pin wise */
#define I2C_DATA PORT0.PIN0
#define I2C_CLK PORT0.PIN1
#define HIGH 1
#define LOW 0
/* I2C Start - bit bang */
void I2C_START(void)
{
/* I2C Start condition, data line goes low when clock is high */
I2C_DATA = HIGH;
I2C_CLK = HIGH;
I2C_DATA = LOW;
I2C_CLK = LOW;
}
/* I2C Stop - bit bang */
void I2C_STOP (void)
{
/* I2C Stop condition, clock goes high when data is low */
I2C_CLK = LOW;
I2C_DATA = LOW;
I2C_CLK = HIGH;
I2C_DATA = HIGH;
}
/* I2C Write - bit bang */
void I2C_WRITE(unsigned char data)
{
unsigned char outBits;
unsigned char inBit;
/* 8 bits */
for(outBits = 0; outBits < 8; outBits++)
{
if(data & 0x80)
I2C_DATA = 1;
else
I2C_DATA = 0;
data <<= 1;
/* Generate clock for 8 data bits */
SCLK = HIGH;
SCLK = LOW;
}
/* Generate clock for ACK */
I2C_CLK = HIGH;
/* Wait for clock to go high, clock stretching */
while(I2C_CLK);
/* Clock high, valid ACK */
inBit = I2C_DATA;
I2C_CLK = LOW;
}
unsigned char I2C_READ (void)
{
unsigned char inData, inBits;
inData = 0x00;
/* 8 bits */
for(inBits = 0; inBits < 8; inBits++)
{
inData <<= 1;
I2C_CLK = HIGH;
inData |= I2C_DATA;
I2C_CLK = LOW;
}
return inData;
}
/* Examble for writing to I2C Slave */
void writeI2CSlave (unsigned char data)
{
/* Start */
I2C_START();
/* Slave address */
I2C_WRITE(0xAA)
/* Slave control byte */
I2C_WRITE(0xBB);
/* Slave data */
I2C_WRITE(data);
/* Stop */
I2C_STOP();
}
/* Examble for reading from I2C Slave */
unsigned char readI2CSlave(unsigned char data)
{
unsigned char inData;
/* Start */
I2C_START();
/* Slave address */
I2C_WRITE(0xAA);
/* Slave control byte */
I2C_WRITE(data);
/* Stop */
I2C_STOP();
/* Start */
I2C_START();
/* Slave address + read */
I2C_WRITE(0xAA | 1);
/* Read */
inData = I2C_READ();
return inData;
}
Simple serial and timer ISR state machine
/*
k164_js.c
Purpose: New firmware for the k164 dtmf decoder board and
the AT89C2051-24PC The source code was compiled with sdcc.
URLs:
http://www.digikey.com/product-detail/en/AT89C2051-24PU/AT89C2051-24PU-ND/1118880
http://www.electronics123.com/kits-and-modules/Telephone-Call-Logger-Kit-16k.html
http://www.kitsrus.com/pdf/k164.pdf
Compile: sdcc k164_js.c ; packihx k164_js.ihx > k164_js.hex
Simulate: s51 k164_js.hex
Copyright (C) 2009 Nu Tech Software Solutions, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
AUTHOR: Sean Mathews <coder at f34r.com> 1/27/2009
*/
#include <at89x051.h>
#define STATUS_LED P3_5
#define HOOK_LED P3_4
#define LOOP_STATUS P3_3
#define STD_STATUS P3_7
#define MODE_SWITCH P1_5
/* UART parameters */
#define CpuClk 20275200 // 20.2752 MHz clock chip on the k164 board
#define Baudrate 9600 // UART - 9600,N,8,1 baud used by current firmware
#define Timer1ReloadValue (256-(2*CpuClk/32/12/Baudrate))
#define F34R_MODE 0
char szVERSION[] = "V1.0";
/*
To determine the value that must be placed in TH1 to generate a given baud rate, we may use the following equation (assuming PCON.7 is clear).
TH1 = 256 - ((Crystal / 384) / Baud)
If PCON.7 is set then the baud rate is effectively doubled, thus the equation becomes:
TH1 = 256 - ((Crystal / 192) / Baud)
make this next macro work and we wont hvae to hard code the values ...
*/
#define InterruptRate 10000 // how oftin to hit our interrupt per second
#define Timer0H 0xBE //(char)((0xFF00 & (65536 - (InterruptRate / 12 * 1000))) >> 8)
#define Timer0L 0x00 //(char)(0x00FF & (65536 - (InterruptRate / 12 * 1000)))
/* prototypes */
void hw_init();
char getchar( void );
void myputchar( char c );
void doevents();
void myputs(char *);
void itoa(int value, char* string, int radix);
void uitoa(unsigned int value, char* string, int radix);
void send_version(void);
void send_hello(void);
void send_help(void);
#define UNKNOWN 0x01
#define OFFHOOK 0x02
#define ONHOOK 0x03
#define VERSION 0x04
#define EGGS 0x05
#define RESET 0x06
#define SEND_HELP 0x07
char hook_state;
char input_state;
int notdone=1;
#define ON 0x02
#define OFF 0x03
char std_state;
static char state_machine_active=0;
/* plug all of the other interrupt vectors */
#ifdef SDCC
void mydummyISR (void) interrupt 12 _naked {
}
#endif
/* Serial interrupt to track incoming key strokes */
void serial_isr(void) interrupt 4 {
if (RI != 0)
{
RI = 0;
if(SBUF == '?')
hook_state = UNKNOWN;
if(SBUF == 'V' || SBUF == 'v')
input_state = VERSION;
if(SBUF == 'R' || SBUF == 'r')
input_state = RESET;
if(SBUF == '!')
input_state = EGGS;
if(SBUF == 'H' || SBUF == 'h')
input_state = SEND_HELP;
}
return;
}
/*-------------------------------------------------------------------------
integer to string conversion
Written by: Bela Torok, 1999 in the public domain
bela.torok@kssg.ch
usage:
uitoa(unsigned int value, char* string, int radix)
itoa(int value, char* string, int radix)
value -> Number to be converted
string -> Result
radix -> Base of value (e.g.: 2 for binary, 10 for decimal, 16 for hex)
---------------------------------------------------------------------------*/
#define NUMBER_OF_DIGITS 16 /* space for NUMBER_OF_DIGITS + '\0' */
void uitoa(unsigned int value, char* string, int radix)
{
unsigned char index, i;
index = NUMBER_OF_DIGITS;
i = 0;
do {
string[--index] = '0' + (value % radix);
if ( string[index] > '9') string[index] += 'A' - ':'; /* continue with A, B,.. */
value /= radix;
} while (value != 0);
do {
string[i++] = string[index++];
} while ( index < NUMBER_OF_DIGITS );
string[i] = 0; /* string terminator */
}
void itoa(int value, char* string, int radix)
{
if (value < 0 && radix == 10) {
*string++ = '-';
uitoa(-value, string, radix);
}
else {
uitoa(value, string, radix);
}
}
/* setup UART */
void hw_init() {
LOOP_STATUS = 1; //set our loop status pin to an input
STD_STATUS = 1; //set our std status pin to an input
MODE_SWITCH = 1; //set the "ECHO" switch input on the K164 board to input
EA = 0; // disable all interrupts
PCON |= 0x80; // SMOD = 1 double speed clock for our baud rate interrupt
TH1 = TL1 = Timer1ReloadValue; // timer 1 mode 1 reload value 9600 baud as calculated in our macro
TMOD &= 0x0f; /* Set timer 1 */
TMOD |= 0x20; /* Set timer 1 as Gate=0 Timer, mode 2 */
TR1 = 1; // turn on serial timer Timer 1
SCON = 0x40; // init port as 8-bit UART with variable baudrate
SCON |= 0x10; // Enabling serial reception
// SCON |= 0x02; // Setting TI bit
ES = 1; // Enable Serial Interrupt */
/* Timer 0 setup */
TMOD &= 0xf0; /* Set timer 0 */
TMOD |= 0x01; /* Set timer 0 16 bit timer */
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L; // reload with 35711 for 1Hz
TR0 = 1; // turn on timer 0
ET0 = 1; // Enable timer 0 interrupt
RI = 0;
TI = 1;
EA = 1; // enable all interrupts
}
/* setup FIRMWARE */
void fw_init() {
/* initialize our state machine to ON HOOK */
hook_state = UNKNOWN;
input_state = UNKNOWN;
std_state = UNKNOWN;
/* Turn off our LED's we just started */
HOOK_LED = 0;
STATUS_LED = 0;
}
/* read a character from UART */
char getchar( void ) {
while(!RI);
RI = 0;
return(SBUF);
}
/* send a character to UART port */
void myputchar( char c ) {
while(!TI);
TI =0;
SBUF = c;
}
void myputs(char *sz) {
while(*sz) myputchar(*sz++);
}
/* Timer 0 interrupt the state machines main interrupt */
void timer_isr(void) interrupt 1 {
static int suppressfirst=1;
static int x=0;
static int counter=0;
char buffer[17];
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L;
/* every 1 second do our event routine */
if(x++>50) {
x=0;
doevents();
}
/* we need to control this or we will be trying to send out serial data from two threads */
if(state_machine_active) {
if( input_state == VERSION ) {
send_version();
input_state = UNKNOWN;
}
if( input_state == SEND_HELP ) {
send_help();
input_state = UNKNOWN;
}
if( input_state == EGGS ) {
myputs("! Jack Edin 1961-2012 rip - Logic Unlimited !\r\n");
myputs("! Sean Mathews - NuTech.com !\r\n");
input_state = UNKNOWN;
}
if( input_state == RESET ) {
notdone=0;
input_state = UNKNOWN;
}
/* check state of the hook line it seems to be inverted */
if(!LOOP_STATUS) {
HOOK_LED = 1; /* ON NPN Transistor base*/
if( hook_state != OFFHOOK ) {
counter++;
if(counter>10) { // 100ms
hook_state = OFFHOOK;
if(!suppressfirst) {
myputs("OFFHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
} else {
HOOK_LED = 0; /* OFF NPN Transistor base*/
counter=0;
if( hook_state != ONHOOK ) {
hook_state = ONHOOK;
if(!suppressfirst) {
myputs("ONHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
/* check state of the STD pin on the MT8870CE chip */
if(STD_STATUS) {
if( std_state != ON ) {
std_state = ON;
if(MODE_SWITCH==F34R_MODE) {
myputs("TONE ");
}
switch(P1 & 0x0f) {
case 10:
buffer[0]='0';
buffer[1]=0;
break;
case 11:
buffer[0]='*';
buffer[1]=0;
break;
case 12:
buffer[0]='#';
buffer[1]=0;
break;
default:
itoa(P1 & 0x0f,buffer,10);
break;
}
myputs(buffer);
if(MODE_SWITCH==F34R_MODE) {
myputs("\r\n");
}
}
} else {
if( std_state != OFF ) {
std_state = OFF;
}
}
}
}
/* Event routine for periodic processing */
void doevents() {
static char flipflop=0;
/* one second event handler. Future use...*/
/* flash the status led every 1 second */
if(MODE_SWITCH!=F34R_MODE) {
STATUS_LED = !STATUS_LED;
} else {
flipflop = !flipflop;
if(flipflop)
STATUS_LED = !STATUS_LED;
}
}
/* MAIN */
void main(void) {
notdone=1;
/* first setup our states and any other startup code so
when our hardware calls our routines they are ready */
fw_init();
/* ok now setup our hardware and start the interrupts */
hw_init();
/* tell the world we are up and running */
send_hello();
/* let the state machine go */
state_machine_active=1;
/* ... */
while (notdone) { }
// disable all interrupts
EA = 0;
// jump to 0
((void (code *)(void)) 0) ();
}
void send_hello() {
myputs("\r\n! K164mh Telephone DTMF Decoder ");
myputs(szVERSION);
myputs(" written for my good friend Jack Edin 1961-2012 rip!\r\n");
}
void send_version() {
myputs(szVERSION);
myputs("\r\n");
}
void send_help() {
myputs("\r\n! Every line that starts with a ! is considered informational\r\n!and is not part of any call logging.\r\n");
myputs("! The state messages are ONHOOK [%1], OFFHOOK, TONE %1\r\n");
myputs("! The tones can also be on the ONHOOK line if the device is in inbound calls mode\r\n");
myputs("! K164mh commands: \r\n! ? = Information\r\n! V = Version\r\n! R = Reset\r\n! H = This info\r\n");
}
PID Control
// PID Control program by Bill Keenan, Melbourne
// Throttle PID loop stuff
#define Umin -1022
#define Umax 1022
#define Kp 0.5 //
#define Ki 0.005 //
#define Kd 1.25 //
float U0 = 0;
float integ; // integration part of PID-loop must be saved
float ep; // previous error used for differential error (e - ep)
/*****************************************************************************/
float prop, junk, der; //
// junk, U0, Umax, Umin, Kp, Ki, err.
int throttle_pidloop(int realpos) // PID-loop calc
// integ - integral part of controller
// ep - preceding control error
// realpos - throttle position feedback
// Besides this function uses global variables such as:
// Kp,Ki,Kd,U0 - constants of controller;
// accel_use - setpoint
// Umin,Umax - range of the output control signal
{
int output;
float error; // actual control error
error = (float)(accel_use - realpos); // calculation of actual error
der = ((error - ep) * Kd);
prop = error * Kp; // calculation of proportional part
if(prop > 1022)
{
prop = 1022;
}
if(prop < -1022)
{
prop = -1022;
}
junk = error * Ki; // calculation of integral part
integ = integ + junk;
if ((int)integ > Umax)
{
integ = (float)Umax;
}
else if ((int)integ < Umin)
{
integ = (float)Umin;
}
output = (int)(prop + integ + der);
if (output > Umax)
{
output = Umax;
}
else if (output < Umin)
{
output = Umin;
}
ep = error; // new error
return(output); // return the object controlling magnitude
}
Fast non-754 floating point library for Freescale 56F800E series
#ifndef ALREADY_READ_FFLOATV2A_H
#define ALREADY_READ_FFLOATV2A_H
/*******************************************************************************
FFloat Number Definitions
*******************************************************************************/
#define MINUSONEFF 0x00008000 //FFloat number -1
#define ZEROFF 0xFF800000 //FFloat number 0
#define ONEFF 0x00014000 //FFloat number 1
#define TWOFF 0x00024000 //FFloat number 2
#define THREEFF 0x00026000 //FFloat number 3
#define FOURFF 0x00034000 //FFloat number 4
#define FIVEFF 0x00035000 //FFloat number 5
#define SIXFF 0x00036000 //FFloat number 6
#define SEVENFF 0x00037000 //FFloat number 7
#define EIGHTFF 0x00044000 //FFloat number 8
#define NINEFF 0x00044800 //FFloat number 9
#define TENFF 0x00045000 //FFloat number 10
#define ELEVENFF 0x00045800 //FFloat number 11
#define TWELVEFF 0x00046000 //FFloat number 12
#define NOMINALBATVOLTAGE 0x00044800
/*******************************************************************************
FFloat Data Type Definition
*******************************************************************************/
typedef unsigned char bool;
typedef long unsigned int ffloat;
/*******************************************************************************
FFloat FUNCTION PROTOTYPES
*******************************************************************************/
asm ffloat FFabs(register ffloat ffnum);
asm ffloat FFneg(register ffloat ffnum);
asm ffloat S16int2FFloat(register short int inum);
asm ffloat S32int2FFloat(register long int inum);
asm ffloat U32int2FFloat(register long unsigned int unum);
asm ffloat FFadd(register ffloat ffnum1,register ffloat ffnum2);
asm ffloat FFdiv(register ffloat ffnum1,register ffloat ffnum2);
asm short int FFloatTrunc2S16int(register ffloat ffnum);
asm short int FFloatRnd2S16int(register ffloat ffnum);
asm ffloat FFmult(register ffloat ffnum1,register ffloat ffnum2);
asm ffloat FFsub(register ffloat ffnum1,register ffloat ffnum2);
asm ffloat IEEE2FFloat(register float fnum);
float FFloat2IEEE(ffloat ffnum);
asm bool FFgt(register ffloat ffnum1, register ffloat ffnum2);
asm bool FFlt(register ffloat ffnum1, register ffloat ffnum2);
asm bool FFgte(register ffloat a, register ffloat b);
asm bool FFlte(register ffloat a, register ffloat b);
asm bool FFgtz(register ffloat ffnum);
asm bool FFltz(register ffloat ffnum);
asm bool FFeqz(register ffloat ffnum);
ffloat FFatan(ffloat xin);
ffloat FFsin(ffloat xin);
ffloat FFcos(ffloat xin);
#endif
**********************************************************
Function code begins below
**********************************************************
#include "FFloatV2A.h"
ffloat FFatan(ffloat xin)
{
int k,klo,khi;
ffloat xdiff0, xdiff1;
ffloat x=xin;
static ffloat xlo = 0x0005b000;
static ffloat xhi = 0x00055000;
static ffloat ya[151] = {0x00019eaa, 0x00019eb5, 0x00019ec0, 0x00019ecc, 0x00019ed8, 0x00019ee4, 0x00019ef1, 0x00019efe, 0x00019f0c, 0x00019f19, 0x00019f28, 0x00019f36, 0x00019f46, 0x00019f55, 0x00019f66, 0x00019f76, 0x00019f88, 0x00019f99, 0x00019fac, 0x00019fbf, 0x00019fd3, 0x00019fe8, 0x00019ffd, 0x0001a013, 0x0001a02a, 0x0001a042, 0x0001a05b, 0x0001a075, 0x0001a090, 0x0001a0ac, 0x0001a0ca, 0x0001a0e9, 0x0001a109, 0x0001a12b, 0x0001a14e, 0x0001a173, 0x0001a19a, 0x0001a1c3, 0x0001a1ee, 0x0001a21c, 0x0001a24c, 0x0001a27f, 0x0001a2b5, 0x0001a2ef, 0x0001a32c, 0x0001a36d, 0x0001a3b3, 0x0001a3fd, 0x0001a44d, 0x0001a4a2, 0x0001a4ff, 0x0001a563, 0x0001a5d0, 0x0001a646, 0x0001a6c7, 0x0001a754, 0x0001a7f0, 0x0001a89d, 0x0001a95d, 0x0001aa33, 0x0001ab25, 0x0001ac37, 0x0001ad71, 0x0001aeda, 0x0001b07f, 0x0001b26e, 0x0001b4bc, 0x0001b785, 0x0001baf1, 0x0001bf38, 0x0000894e, 0x00009757, 0x0000a9a2, 0xffff8292, 0xffffbd49, 0xff800000, 0xffff42b6, 0xffff7d6d, 0x0000565d, 0x000068a8, 0x000076b1, 0x000140c7, 0x0001450e, 0x0001487a, 0x00014b43, 0x00014d91, 0x00014f80, 0x00015125, 0x0001528e, 0x000153c8, 0x000154da, 0x000155cc, 0x000156a2, 0x00015762, 0x0001580f, 0x000158ab, 0x00015938, 0x000159b9, 0x00015a2f, 0x00015a9c, 0x00015b00, 0x00015b5d, 0x00015bb2, 0x00015c02, 0x00015c4c, 0x00015c92, 0x00015cd3, 0x00015d10, 0x00015d4a, 0x00015d80, 0x00015db3, 0x00015de3, 0x00015e11, 0x00015e3c, 0x00015e65, 0x00015e8c, 0x00015eb1, 0x00015ed4, 0x00015ef6, 0x00015f16, 0x00015f35, 0x00015f53, 0x00015f6f, 0x00015f8a, 0x00015fa4, 0x00015fbd, 0x00015fd5, 0x00015fec, 0x00016002, 0x00016017, 0x0001602c, 0x00016040, 0x00016053, 0x00016066, 0x00016077, 0x00016089, 0x00016099, 0x000160aa, 0x000160b9, 0x000160c9, 0x000160d7, 0x000160e6, 0x000160f3, 0x00016101, 0x0001610e, 0x0001611b, 0x00016127, 0x00016133, 0x0001613f, 0x0001614a, 0x00016155};
static ffloat y2a[151] = {0xff800000, 0xfff443e4, 0xfff446b6, 0xfff449b0, 0xfff44cd5, 0xfff45029, 0xfff453af, 0xfff4576a, 0xfff45b5f, 0xfff45f92, 0xfff46408, 0xfff468c6, 0xfff46dd1, 0xfff47331, 0xfff478ec, 0xfff47f0a, 0xfff542c9, 0xfff54648, 0xfff54a06, 0xfff54e0a, 0xfff55259, 0xfff556fa, 0xfff55bf6, 0xfff56156, 0xfff56722, 0xfff56d66, 0xfff5742f, 0xfff57b8a, 0xfff641c3, 0xfff6461c, 0xfff64ad8, 0xfff65004, 0xfff655ac, 0xfff65be0, 0xfff662b0, 0xfff66a30, 0xfff67278, 0xfff67ba1, 0xfff742e5, 0xfff7488b, 0xfff74ed9, 0xfff755e6, 0xfff75dd0, 0xfff766ba, 0xfff770cc, 0xfff77c39, 0xfff8449e, 0xfff84c0f, 0xfff8549c, 0xfff85e7b, 0xfff869ef, 0xfff8774e, 0xfff9437f, 0xfff94cc5, 0xfff957cc, 0xfff96504, 0xfff974fc, 0xfffa4439, 0xfffa5032, 0xfffa5f16, 0xfffa71cd, 0xfffb44d0, 0xfffb542e, 0xfffb684a, 0xfffc4182, 0xfffc538f, 0xfffc6c5c, 0xfffd4779, 0xfffd5fe2, 0xfffe4133, 0xfffe5918, 0xfffe77b6, 0xffff4b62, 0xffff503a, 0xfffe707d, 0xff800000, 0xfffe8f82, 0xffffafc5, 0xffffb49d, 0xfffe8849, 0xfffea6e7, 0xfffebecc, 0xfffda01d, 0xfffdb886, 0xfffc93a3, 0xfffcac70, 0xfffcbe7d, 0xfffb97b5, 0xfffbabd1, 0xfffbbb2f, 0xfffa8e32, 0xfffaa0e9, 0xfffaafcd, 0xfffabbc6, 0xfff98b03, 0xfff99afb, 0xfff9a833, 0xfff9b33a, 0xfff9bc80, 0xfff888b1, 0xfff89610, 0xfff8a184, 0xfff8ab63, 0xfff8b3f0, 0xfff8bb61, 0xfff783c6, 0xfff78f33, 0xfff79945, 0xfff7a22f, 0xfff7aa19, 0xfff7b126, 0xfff7b774, 0xfff7bd1a, 0xfff6845e, 0xfff68d87, 0xfff695cf, 0xfff69d4f, 0xfff6a41f, 0xfff6aa53, 0xfff6affb, 0xfff6b527, 0xfff6b9e3, 0xfff6be3c, 0xfff58475, 0xfff58bd0, 0xfff59299, 0xfff598dd, 0xfff59ea9, 0xfff5a409, 0xfff5a905, 0xfff5ada6, 0xfff5b1f5, 0xfff5b5f9, 0xfff5b9b7, 0xfff5bd36, 0xfff480f5, 0xfff48713, 0xfff48cce, 0xfff4922e, 0xfff49739, 0xfff49bf7, 0xfff4a06d, 0xfff4a4a0, 0xfff4a895, 0xfff4ac50, 0xfff4afd6, 0xfff4b32a, 0xfff4b64f, 0xfff4b949, 0xfff4bc1b, 0xfff4bc1b};
static int numpoints = 151;
static ffloat h = 0xffff4444;
static ffloat hinv = 0x00027800;
klo = FFloatTrunc2S16int(FFmult(FFsub(x,xlo),hinv));
khi=klo+1;
if(FFlt(x,xlo)){
return(ya[0]);
}else if(FFgt(x,xhi)){
return(ya[numpoints-1]);
}
xdiff0 = FFsub(x, FFadd(xlo, FFmult(h,S16int2FFloat(klo))));
xdiff1 = FFsub(xdiff0, h);
return ( FFadd(ya[klo], FFadd(FFmult(FFmult(FFsub(ya[khi],ya[klo]), hinv), xdiff0), FFmult(FFmult(y2a[khi], xdiff0), xdiff1))) );
}
ffloat FFcos(ffloat xin)
{
int k,klo,khi;
ffloat xdiff0, xdiff1;
ffloat x=xin;
static ffloat xlo = 0x00029b78;
static ffloat xhi = 0x00026487;
static ffloat ya[31] = {0x00008000, 0x000082cc, 0x00008b10, 0x00009872, 0x0000aa59, 0xffff8000, 0xffffb0e4, 0xfffd94f6, 0xfffd6b09, 0xffff4f1b, 0x00004000, 0x000055a6, 0x0000678d, 0x000074ef, 0x00007d33, 0x00014000, 0x00007d33, 0x000074ef, 0x0000678d, 0x000055a6, 0x00004000, 0xffff4f1b, 0xfffd6b09, 0xfffd94f6, 0xffffb0e4, 0xffff8000, 0x0000aa59, 0x00009872, 0x00008b10, 0x000082cc, 0x00008000};
static ffloat y2a[31] = {0xff800000, 0xffff7cbe, 0xffff7481, 0xffff672d, 0xffff5556, 0xfffe7f88, 0xfffe4ed1, 0xfffc6aa5, 0xfffc955a, 0xfffeb12e, 0xfffe8077, 0xffffaaa9, 0xffff98d2, 0xffff8b7e, 0xffff8341, 0xffff8077, 0xffff8341, 0xffff8b7e, 0xffff98d2, 0xffffaaa9, 0xfffe8077, 0xfffeb12e, 0xfffc955a, 0xfffc6aa5, 0xfffe4ed1, 0xfffe7f88, 0xffff5556, 0xffff672d, 0xffff7481, 0xffff7cbe, 0xffff7cbe};
static int numpoints = 31;
static ffloat h = 0xfffe6b3b;
static ffloat hinv = 0x00034c64;
static ffloat pi2=0x00036487;
static ffloat pi2inv=0xfffe517c;
if(FFlt(xin,xlo)){
x=FFadd(
xin,
FFmult(
S16int2FFloat(
FFloatTrunc2S16int(
FFmult(
FFsub(xhi,xin),
pi2inv
)
)
),
pi2
)
);
}else if(FFgt(xin,xhi)){
x=FFsub(
xin,
FFmult(
S16int2FFloat(
FFloatTrunc2S16int(
FFmult(
FFsub(xin,xlo),
pi2inv
)
)
),
pi2
)
);
}
klo = FFloatTrunc2S16int(FFmult(FFsub(x,xlo),hinv));
khi=klo+1;
xdiff0 = FFsub(x, FFadd(xlo, FFmult(h,S16int2FFloat(klo))));
xdiff1 = FFsub(xdiff0, h);
return ( FFadd(ya[klo], FFadd(FFmult(FFmult(FFsub(ya[khi],ya[klo]), hinv), xdiff0), FFmult(FFmult(y2a[khi], xdiff0), xdiff1))) );
}
//Return the negative of ffnum
asm ffloat FFneg(register ffloat ffnum)
{
move.w A1,Y0 //store ffnum exp in Y0
move.w A0,A //A holds mantissa of ffnum
neg A //full 36-bit negate
asr A //shift right to prevent overflow of clb
jeq Zero //Don't normalize if zero
//ffnum != 0
clb A,X0 //Count sign bits
asll.l X0,A //Normalize
sub X0,Y0 //Adjust exponent
inc.w Y0 //Return to normal scale
clb Y0,X0 //check number of sign bits in exponent
cmp.w #8,X0 //If less than 8 (exp > 8 bits),
jlt Exp_Err //jump to exponent exception handler
Continue:
rtsd //delayed return from subroutine
move.w A1,A0 //Move mantissa of sum to lower word of ffnum1 (return value)
move.w Y0,A1 //Move exponent to upper word of ffnum1 (return value)
sxt.l A //Sign-extend A to 36 bits
//end of main neg function
Zero:
rtsd //Delayed return from subroutine - will execute next three words
move.w #$FF80,A //Set exp of sum to minimum
clr.w A0 //Set mantissa of sum to 0
//end of zero handler
Exp_Err:
cmp.w #$007F,Y0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop //Delay slot filler
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three cycles
move.w #$8000,A0 //Most negative mantissa
nop //Delay slot filler
//end
Underflow:
cmp.w #$FF80,Y0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
}
//Return the absolute value of ffnum
asm ffloat FFabs(register ffloat ffnum)
{
move.w A1,Y0 //store ffnum exp in Y0
move.w A0,A //A holds mantissa of ffnum
abs A //full-width absolute value
asr A //shift right to prevent overflow of clb
jeq Zero //Don't normalize if zero
//ffnum != 0
clb A,X0 //Count sign bits
asll.l X0,A //Normalize
sub X0,Y0 //Adjust exponent
inc.w Y0 //Return to normal scale
clb Y0,X0 //check number of sign bits in exponent
cmp.w #8,X0 //If less than 8 (exp > 8 bits),
jlt Exp_Err //jump to exponent exception handler
Continue:
rtsd //delayed return from subroutine
move.w A,A0 //Move mantissa of sum to lower word of ffnum1 (return value)
move.w Y0,A1 //Move exponent to upper word of ffnum1 (return value)
sxt.l A //Sign-extend A to 36 bits
//end of main abs function
Zero:
rtsd //Delayed return from subroutine - will execute next three words
move.w #$FF80,A //Set exp of sum to minimum
clr.w A0 //Set mantissa of sum to 0
//end of zero handler
Exp_Err:
cmp.w #$007F,Y0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop //Delay slot filler
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three cycles
move.w #$8000,A0 //Most negative mantissa
nop //Delay slot filler
//end
Underflow:
cmp.w #$FF80,Y0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
}
//convert an int16 to an ffloat value
asm ffloat S16int2FFloat(register short int inum)
{
tst.w Y0
jeq Zero
//inum != 0
clb Y0,X0
asll.l X0,Y0 //normalize inum
neg X0 //set exponent
rtsd
add.w #15,X0
move.w X0,A //exponent
move.w Y0,A0 //mantissa
//FFloat zero = 0xFF800000
Zero:
rtsd
move.w #$FF80,A
clr.w A0
}
asm ffloat FFadd(register ffloat ffnum1,register ffloat ffnum2)
{
move.w A0,X0 //Store ffnum1 mantissa temporarily in X0
move.w B0,Y0 //Store ffnum2 mantissa temporarily in Y0
move.w A1,Y1 //Put ffnum1 exponent (exp1) in Y1
sub B,Y1 //Y1 = exp1 - exp2
//Setup: Larger ffnum exponent goes in Y0; mantissa to be shifted goes in B1;
//mantissa to stay the same goes in A1; abs exp difference goes in Y1
tlt B,A //Move ffnum2 (mantissa and exp) to A (not shifted) if Y1 neg
tlt X0,B //Move ffnum1 mantissa to B1 for shifting if Y1 neg
tge Y0,B //Move ffnum2 mantissa to B1 for shifting if Y1 not negative
abs Y1 //positive shift values
cmp.w #15,Y1 //More than 15-bit shift (ASRAC only works to 15 bits)?
jgt Neglect //If yes, an input ffnum will go to zero if shifted
move.w A1,Y0 //Move larger exp to Y0 for shifting
move.w A0,A //Move mantissa A0 to A1 for adding
asrac B1,Y1,A //Extend B1 to 36 bits, shift right by Y1, and add to A
asr A //Shift right to prevent overflow of CLB (next)
clb A,X0 //Count sign bits
asll.l X0,A //Normalize
tst.w A1 //Check if relevant part of result is zero
jeq Zero //Result is zero
sub X0,Y0 //Adjust exponent of exp1
inc.w Y0 //Return to normal scale
clb Y0,X0 //check number of sign bits in exponent
cmp.w #8,X0 //If less than 8 (exp > 8 bits),
jlt Exp_Err //jump to exponent exception handler
Continue:
rnd A //round to 16 bits in A1
rtsd //delayed return from subroutine
move.w A,A0 //Move mantissa of sum to lower word of ffnum1 (return value)
move.w Y0,A1 //Move exponent to upper word of ffnum1 (return value)
sxt.l A //Sign-extend A to 36 bits
//end of main add function
Zero:
rtsd //Delayed return from subroutine - will execute next three words
move.w #$FF80,A //Set exp of sum to minimum
clr.w A0 //Set mantissa of sum to 0
//end of zero handler
Exp_Err:
cmp.w #$007F,Y0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop //Delay slot filler
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three cycles
move.w #$8000,A0 //Most negative mantissa
nop //Delay slot filler
//end
Underflow:
cmp.w #$FF80,Y0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
Neglect:
rts //The input with the larger exp becomes the output
}
asm ffloat FFdiv(register ffloat ffnum1, register ffloat ffnum2)
{
move.w A1,X0 //Move exponent of ffnum1 to X0
move.w B1,Y0 //Move exponent of ffnum2 to Y0
move.w A0,Y1 //Move mantissa of ffnum1 to Y1 for sign check
move.w A0,A //Move mantissa of ffnum1 to A1
move.w B0,B //Move mantissa of ffnum2 to B1
eor.w B,Y1 //Calculate sign of final result
//(sign bit of result will be 1=negative if inputs signs differ)
abs A
abs B
jeq DivZero //ffnum2 cannot be zero
L1:
cmp A,B //Check result of B - A
bgt L2 //Ready to divide
brad L1 //Recheck (delayed branch)
asr A //Reduce ffnum1 mantissa by factor of 2
inc.w X0 //Increase ffnum1 exponent by one
//end
L2:
//Division of Positive Fractional Data (A1:A0 / B1)
BFCLR #$0001,SR //Clear carry bit: required for 1st DIV instruction
//REP #16
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
DIV B1,A //Form positive quotient in A0
move.w A0,A //Move A0 to A1
tst.w Y1 //Check sign needed for final result
BGE L3 //Branch if final sign is non-neg
NEG A //Negate mantissa if result is neg
L3:
clb A,Y1 //Count sign bits
asll.l Y1,A //Normalize
tst A //Check if relevant part of result is zero
jeq Zero //Result is zero
sub Y0,X0 //Adjust exponent of exp1
sub Y1,X0
clb X0,Y0 //check size of exponent word
cmp.w #8,Y0
jlt Exp_Err
Continue:
RTSD
MOVE.W A,A0
MOVE.W X0,A1
sxt.l A //Sign-extend A to 36 bits
//END
DivZero:
//Call error handler here
MOVE.W #$007F,A //Needs work here
RTSD
MOVE.W #$7FFF,A0
NOP
//END
Zero:
RTSD
MOVE.W #$FF80,A
CLR.W A0
//END
Exp_Err:
cmp.w #$007F,X0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$8000,A0 //Most negative mantissa
nop //filler for third delay slot
//end
Underflow:
cmp.w #$FF80,X0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
}
asm short int FFloatRnd2S16int(register ffloat ffnum)
{
move.w A1,Y0
move.w A0,A
//Scale so that exponent = 15; converts mantissa to integer scale
//Check if resulting mantissa is in range -32768 to 32767 (16 bit signed int)
sub.w #15,Y0
jgt Over //Number is outside range -32768 to 32767
cmp.w #-17,Y0
jlt Zero //Number is small and rounds to zero
rtsd
asll.l Y0,A //Scale to exponent = 15 (one word, two cycles)
rnd A //Convergent rounding (round down boundary case if even)
move.w A1,Y0
//end
Zero:
rtsd
clr.w Y0 //Result is zero
nop
nop
//end
Over:
tst A
blt Neg //branch to Neg: if number is below -32768
rtsd
move.w #$7FFF,Y0 //Set to most positive 16-bit value
nop //Filler for third delay slot
//end
Neg:
rtsd
move.w #$8000,Y0 //Set to most negative 16-bit value
nop //Filler for third delay slot
//end
}
asm short int FFloatTrunc2S16int(register ffloat ffnum)
{
move.w A1,Y0
move.w A0,A
//Scale so that exponent = 15; converts mantissa to integer scale
//Check if resulting mantissa is in range -32768 to 32767 (16 bit signed int)
sub.w #15,Y0
jgt Over //Number is outside range -32768 to 32767
cmp.w #-17,Y0
jlt Zero //Number is small and rounds to zero
rtsd
asll.l Y0,A //Scale to exponent = 15 (one word, two cycles)
move.w A1,Y0
nop //Filler for third delay slot
//end
Zero:
rtsd
clr.w Y0 //Result is zero
nop
nop
//end
Over:
tst A
blt Neg //branch to Neg: if number is below -32768
rtsd
move.w #$7FFF,Y0 //Set to most positive 16-bit value
nop //Filler for third delay slot
//end
Neg:
rtsd
move.w #$8000,Y0 //Set to most negative 16-bit value
nop //Filler for third delay slot
//end
}
//convert an unsigned int32 to an ffloat value
asm ffloat U32int2FFloat(register long unsigned int unum)
{
tst.l A
jeq Zero //unum = 0
jlt LongUnsigned //If 2^31 <= unum <= 2^32-1, unum will
//be a negative number
//unum <= 2^31 - 1
clb A,X0
asll.l X0,A //normalize unum
neg X0 //set exponent
add.w #31,X0
rtsd
move.w A1,A0 //mantissa
move.w X0,A1 //exponent
sxt.l A //sign-extend A to 36 bits
//FFloat zero = 0xFF800000
Zero:
rtsd
move.w #$FF80,A
clr.w A0
//If unum is between 2^31 and 2^32-1
LongUnsigned:
lsr.w A //divide mantissa by 2
move.w A1,A0 //move mantissa to its right place
//divide the mantissa by two and increase the exponent by 1
//this will correct the sign of A while keeping the absolute
//value of a the same
rtsd
move.w #32,A1 //exponent will always be 32 for this case
sxt.l A //sign-extend A to 36 bits
}
//convert an int32 to an ffloat value
asm ffloat S32int2FFloat(register long int inum)
{
//inum = 0
tst.l A
jeq Zero
//inum != 0
clb A,X0
asll.l X0,A //normalize inum
neg X0 //set exponent
add.w #31,X0
rtsd
move.w A1,A0 //mantissa
move.w X0,A1 //exponent
sxt.l A //sign-extend A to 36 bits
//FFloat zero = 0xFF800000
Zero:
rtsd
move.w #$FF80,A
clr.w A0
}
//typedef long unsigned int ffloat;
asm ffloat FFmult(register ffloat ffnum1, register ffloat ffnum2)
{
move.w B1,Y1 //This is to save exp2, use B for mult, and prepare for exp add
move.w A0,X0 //Can't multiply A0,B0 directly
move.w B0,Y0
mpyr X0,Y0,B //Multiply with round; result unlikely to differ from mpy, since truncated later
asr B //Shift right, so CLB can give correct count
clb B,X0 //Count sign bits for normalization
asll.l X0,B //Normalize
tst.w B1 //Check if relevant part of result is zero
jeq Zero //Go to zero handler
add A,Y1 //add A1 to Y1
sub X0,Y1 //Update exponent after normalization
inc.w Y1 //Return to normal scale
clb Y1,Y0 //count sign bits in exponent word
cmp.w #8,Y0 //If <8 (exp > 8 bits),
jlt Exp_Err //jump to exponent exception handler
Continue:
rtsd //return with 3-cyle delay
move.w Y1,A //Put exp in return register
rnd B //Round to 16 bits in B1
move.w B1,A0 //Move mantissa to A0
//end of mult routine
Zero:
rtsd //return with 3-cyle delay
move.w #$FF80,A //Set exp of sum to minimum
clr.w A0 //Set mantissa of sum to 0
//end of zero handler
Exp_Err:
cmp.w #$007F,Y1 //Check for overflow
jle Underflow //If not overflow, go to underflow check
tst.w B1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$7FFF,A0 //Max out mantissa
rtsd //Delayed return - will execute next three words
nop //Filler for third delay slot
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return - will execute next three words
move.w #$8000,A0 //Most negative mantissa
nop //Filler for third delay slot
//end
Underflow:
cmp.w #$FF80,Y1 //Check for underflow
jge Continue //Not an error - continue normal code
tst.w B1 //Positive or negative overflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return - will execute next three words
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //Filler for third delay slot
//end of Exp_Err
}
asm ffloat FFsub(register ffloat ffnum1,register ffloat ffnum2)
{
move.w A0,X0 //Store ffnum1 mantissa temporarily in X0
move.w B1,Y1 //Store ffnum2 mantissa temporarily in Y1
move.w B0,B //Prepare to negate B
asr B //Prevent overflow
inc.w Y1 //Adjust exponent
neg B //Negate
clb B,Y0 //Count leading bits
asll.l Y0,B //rescale
sub Y0,Y1 //adjust exponent
move.w B1,Y0
move.w Y1,B
move.w Y0,B0
move.w A1,Y1 //Put ffnum1 exponent (exp1) in Y1
sub B,Y1 //Y1 = exp1 - exp2
//Setup: Larger ffnum exponent goes in Y0; mantissa to be shifted goes in B1;
//mantissa to stay the same goes in A1; abs exp difference goes in Y1
tlt B,A //Move ffnum2 (mantissa and exp) to A (not shifted) if Y1 neg
tlt X0,B //Move ffnum1 mantissa to B1 for shifting if Y1 neg
tge Y0,B //Move ffnum2 mantissa to B1 for shifting if Y1 not negative
abs Y1 //positive shift values
cmp.w #15,Y1 //More than 15-bit shift (ASRAC only works to 15 bits)?
jgt Neglect //If yes, an input ffnum will go to zero if shifted
move.w A1,Y0 //Move larger exp to Y0 for shifting
move.w A0,A //Move mantissa A0 to A1 for adding
asrac B1,Y1,A //Extend B1 to 36 bits, shift right by Y1, and add to A
asr A //Shift right to prevent overflow of CLB (next)
clb A,X0 //Count sign bits
asll.l X0,A //Normalize
tst.w A1 //Check if relevant part of result is zero
jeq Zero //Result is zero
sub X0,Y0 //Adjust exponent of exp1
inc.w Y0 //Return to normal scale
clb Y0,X0 //check size of exponent word
cmp.w #8,X0
jlt Exp_Err
Continue:
rnd A //Round to 16 bits
rtsd //delayed return from subroutine
move.w A,A0 //Move mantissa of sum to lower word of ffnum1 (return value)
move.w Y0,A1 //Move exponent to upper word of ffnum1 (return value)
sxt.l A //Sign-extend A to 36 bits
//end of main add function
Zero:
rtsd //Delayed return from subroutine - will execute next three inst.
move.w #$FF80,A //Set exp of sum to minimum
clr.w A0 //Set mantissa of sum to 0
//end of zero handler
Exp_Err:
cmp.w #$007F,Y0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop //filler for third delay slot
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$8000,A0 //Most negative mantissa
nop //filler for third delay slot
//end
Underflow:
cmp.w #$FF80,Y0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU //If negative, go to negative handler
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three inst.
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three inst.
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
Neglect:
rts //The input with the larger exp becomes the output
}
asm ffloat IEEE2FFloat(register float fnum)
{
bftstl #$7F80,A1
jcs Zero //For IEEE, zero is indicated by zero exp.
move.w A1,Y0
bfclr #$FF00,A1
sxt.l A //Sign-extend A to 36 bits
bfset #$0080,A1
brclr #$8000,Y0,L1 //Branch if sign bit is positive
neg A //Negate mantissa if sign bit is negative
L1:
clb A,X0 //Normalize mantissa
asll.l X0,A
bfclr #$807F,Y0
lsrr.w #7,Y0
sub.w #119,Y0
sub X0,Y0 //FFloat exponent is ready
clb Y0,X0 //Check for overflow/underflow
cmp.w #8,X0
jlt Exp_Err
Continue:
rnd A
rtsd
move.w A,A0
move.w Y0,A1
sxt.l A //Sign-extend A to 36 bits
//end
Zero:
RTSD
MOVE.W #$FF80,A
CLR.W A0
//END
Exp_Err:
cmp.w #$007F,Y0
jle Underflow //If not overflow, go to underflow check
tst.w A1 //Positive or negative overflow?
jlt NegO //If negative, go to negative handler
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$7FFF,A0 //Max out mantissa
nop //filler for third delay slot
//end
NegO:
move.w #$007F,A //Max out exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$8000,A0 //Most negative mantissa
nop //filler for third delay slot
//end
Underflow:
cmp.w #$FF80,Y0 //Check for underflow
jge Continue //Not an error
tst.w A1 //Positive or negative underflow?
jlt NegU
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$4000,A0 //Minimum normalized positive mantissa
nop //Filler for third delay slot
//end
NegU:
move.w #$FF80,A //Minimum exponent
rtsd //Delayed return from subroutine - will execute next three words
move.w #$BFFF,A0 //Minimum (abs) normalized negative mantissa
nop //filler for third delay slot
//end of E_Err
}
//A not very good C function. Ok for testing other functions in simulation.
//Converts an FFloat number to an IEEE 754-compatible single precision floating point number.
//typedef long unsigned int ffloat;
float FFloat2IEEE(ffloat ffnum)
{
float fout = 0;
long int iexp = 0;
long unsigned int tempout = 0, sign = 0, mantissa = 0, exp = 0;
void *VoidPointer;
float *FloatPointer;
long unsigned int *LintPointer;
if (ffnum&0xFFFF) //ffnum is not zero
{
mantissa = ffnum & 0x0000FFFF;
exp = ffnum&0xFFFF0000;
iexp = (long int)exp;
iexp += 0x007F0000; //Bias exponent positive by 127
if (iexp < 0x00010000) //Limit exponent size to allowed IEEE range
{
iexp = 0x00010000;
}
else if (iexp > 0x00FE0000)
{
iexp = 0x00FE0000;
}
if (mantissa&0x00008000) //ffnum is negative
{
sign = 0x80000000;
mantissa ^= 0x0000FFFF; //Negate
mantissa++;
}
while (!(mantissa&0x8000)) //normalize
{
mantissa <<= 1;
iexp -= 0x00010000;
}
if (iexp < 0x00010000) //Limit exponent size to allowed IEEE range
{
iexp = 0x00010000;
}
else if (iexp > 0x00FE0000)
{
iexp = 0x00FE0000;
}
exp = (long unsigned int)iexp;
exp <<= 7; //Shift exponent to correct position
mantissa <<= 8; //Shift to correct IEEE position
mantissa &= 0x007FFFFF; //Clear leading one
tempout = sign | exp | mantissa;
}
else exp = 0x00000000; //zero
VoidPointer = &(tempout); //obtain pointer to unsigned long int tempout
FloatPointer = VoidPointer; //convert to float
fout = *FloatPointer;
return(fout);
}
//return true if ffnum1>ffnum2, false otherwise
asm bool FFgt(register ffloat ffnum1, register ffloat ffnum2)
{
//First compare signs of numbers
tst.w A0
blt CheckSignANeg
//a is nonnegative
tst.w B0
//Both numbers are nonnegative - nonnegative exponents case
bge CasePNumExp
//If b is negative, a>b
rtsd
move.w #1,Y0
nop
nop
//a is negative
CheckSignANeg:
tst.w B0
//Both numbers are negative - negative exponents case
blt CaseNNumExp
//If b is nonnegative, a<b
rtsd
move.w #0,Y0
nop
nop
//If a and b are positive, go here
//larger exponent = larger #
CasePNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
blt aGTb //if(expB<expA) then a>b
bgt aNotGTb //if(expB>expA) then !(a>b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
blt aGTb //if(mantissaB<mantissaA) then a>b
rtsd
move.w #0,Y0
nop
nop
//If a and b are negative, go here
//larger exponent = smaller #
CaseNNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
bgt aGTb //if(expB>expA) then a>b
blt aNotGTb //if(expB<expA) then !(a>b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
blt aGTb //if(mantissaB<mantissaA) then a>b
rtsd
move.w #0,Y0
nop
nop
//if a>b, go here
aGTb:
rtsd
move.w #1,Y0
nop
nop
//if a<=b, go here
aNotGTb:
rtsd
move.w #0,Y0
nop
nop
}
//return true if ffnum>0, false otherwise
asm bool FFgtz(register ffloat ffnum)
{
//Test ffnum mantissa
tst.w A0
bgt Positive
//ffnum <= 0
rtsd //delayed return
clr.w Y0 //return value 0
nop //first filler instruction
nop //second filler instruction
//end
Positive:
//ffnum > 0
rtsd //delayed return
move.w #1,Y0 //return value 1
nop //first filler instruction
nop //second filler instruction
//end
}
//return true if ffnum<0, false otherwise
asm bool FFltz(register ffloat ffnum)
{
//Test ffnum mantissa
tst.w A0
blt Negative
//ffnum >= 0
rtsd //delayed return
clr.w Y0 //return value 0
nop //first filler instruction
nop //second filler instruction
//end
Negative:
//ffnum < 0
rtsd //delayed return
move.w #1,Y0 //return value 1
nop //first filler instruction
nop //second filler instruction
//end
}
//return true if ffnum=0, false otherwise
asm bool FFeqz(register ffloat ffnum)
{
//Test ffnum mantissa
tst.w A0
beq Zero
//ffnum != 0
rtsd //delayed return
clr.w Y0 //return value 0
nop //first filler instruction
nop //second filler instruction
//end
Zero:
//ffnum < 0
rtsd //delayed return
move.w #1,Y0 //return value 1
nop //first filler instruction
nop //second filler instruction
//end
}
//return true if ffnum1<ffnum2, false otherwise
asm bool FFlt(register ffloat ffnum1, register ffloat ffnum2)
{
//First compare signs of numbers
tst.w A0
blt CheckSignANeg
//a is nonnegative
tst.w B0
//Both numbers are nonnegative - nonnegative exponents case
bge CasePNumExp
//If b is negative, !(a<b)
rtsd
move.w #0,Y0
nop
nop
//a is negative
CheckSignANeg:
tst.w B0
//Both numbers are negative - negative exponents case
blt CaseNNumExp
//If b is nonnegative, a<b
rtsd
move.w #1,Y0
nop
nop
//If a and b are positive, go here
//larger exponent = larger #
CasePNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
bgt aLTb //if(expB>expA) then a<b
blt aNotLTb //if(expB<expA) then !(a<b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
bgt aLTb //if(mantissaB>mantissaA) then a<b
rtsd
move.w #0,Y0
nop
nop
//If a and b are negative, go here
//larger exponent = smaller #
CaseNNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
blt aLTb //if(expB<expA) then a<b
bgt aNotLTb //if(expB>expA) then !(a<b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
bgt aLTb //if(mantissaB>mantissaA) then a<b
rtsd
move.w #0,Y0
nop
nop
//if a<b, go here
aLTb:
rtsd
move.w #1,Y0
nop
nop
//if a>=b, go here
aNotLTb:
rtsd
move.w #0,Y0
nop
nop
}
//return true if a>=b, false otherwise
asm bool FFgte(register ffloat a, register ffloat b)
{
//First compare signs of numbers
tst.w A0
blt CheckSignANeg
//a is nonnegative
tst.w B0
//Both numbers are nonnegative - nonnegative exponents case
bge CasePNumExp
//If b is negative, a>=b
rtsd
move.w #1,Y0
nop
nop
//a is negative
CheckSignANeg:
tst.w B0
//Both numbers are negative - negative exponents case
blt CaseNNumExp
//If b is nonnegative, a<b
rtsd
move.w #0,Y0
nop
nop
//If a and b are positive, go here
//larger exponent = larger #
CasePNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
blt aGTEb //if(expB<expA) then a>=b
bgt aNotGTEb //if(expB>expA) then !(a>=b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
ble aGTEb //if(mantissaB<=mantissaA) then a>=b
rtsd
move.w #0,Y0
nop
nop
//If a and b are negative, go here
//larger exponent = smaller #
CaseNNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
bgt aGTEb //if(expB>expA) then a>b
blt aNotGTEb //if(expB<expA) then !(a>b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
ble aGTEb //if(mantissaB<=mantissaA) then a>=b
rtsd
move.w #0,Y0
nop
nop
//if a>=b, go here
aGTEb:
rtsd
move.w #1,Y0
nop
nop
//if a<b, go here
aNotGTEb:
rtsd
move.w #0,Y0
nop
nop
}
//return true if a<=b, false otherwise
asm bool FFlte(register ffloat a, register ffloat b)
{
//First compare signs of numbers
tst.w A0
blt CheckSignANeg
//a is nonnegative
tst.w B0
//Both numbers are nonnegative - nonnegative exponents case
bge CasePNumExp
//If b is negative, !(a<=b)
rtsd
move.w #0,Y0
nop
nop
//a is negative
CheckSignANeg:
tst.w B0
//Both numbers are negative - negative exponents case
blt CaseNNumExp
//If b is nonnegative, a<b
rtsd
move.w #1,Y0
nop
nop
//If a and b are positive, go here
//larger exponent = larger #
CasePNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
bgt aLTEb //if(expB>expA) then a<=b
blt aNotLTEb //if(expB>expA) then !(a<=b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
bge aLTEb //if(mantissaB>=mantissaA) then a>=b
rtsd
move.w #0,Y0
nop
nop
//If a and b are negative, go here
//larger exponent = smaller #
CaseNNumExp:
//move exponent data to X0 and Y0 registers for comparison
move.w A1,X0
move.w B1,Y0
cmp.w X0,Y0
blt aLTEb //if(expB<expA) then a<=b
bgt aNotLTEb //if(expB>expA) then !(a<=b)
//If exponents are equal, check mantissas
move.w A0,X0
move.w B0,Y0
cmp.w X0,Y0
bge aLTEb //if(mantissaB>=mantissaA) then a>=b
rtsd
move.w #0,Y0
nop
nop
//if a<=b, go here
aLTEb:
rtsd
move.w #1,Y0
nop
nop
//if a>b, go here
aNotLTEb:
rtsd
move.w #0,Y0
nop
nop
}
ffloat FFsin(ffloat xin)
{
int k,klo,khi;
ffloat xdiff0, xdiff1;
ffloat x=xin;
static ffloat xlo = 0x00029b78;
static ffloat xhi = 0x00026487;
static ffloat ya[31] = {0xffccb968, 0xfffe958c, 0xffff97e0, 0x0000b4c3, 0x0000a0e0, 0x00009126, 0x00008643, 0x000080b3, 0x000080b3, 0x00008643, 0x00009126, 0x0000a0e0, 0x0000b4c3, 0xffff97e0, 0xfffe958c, 0xff800000, 0xfffe6a73, 0xffff681f, 0x00004b3c, 0x00005f1f, 0x00006ed9, 0x000079bc, 0x00007f4c, 0x00007f4c, 0x000079bc, 0x00006ed9, 0x00005f1f, 0x00004b3c, 0xffff681f, 0xfffe6a73, 0xffcc4698};
static ffloat y2a[31] = {0xff800000, 0xfffd6a0f, 0xfffe67be, 0xffff4af6, 0xffff5ec6, 0xffff6e72, 0xffff794a, 0xffff7ed5, 0xffff7ed5, 0xffff794a, 0xffff6e72, 0xffff5ec6, 0xffff4af6, 0xfffe67be, 0xfffd6a0f, 0xff800000, 0xfffd95f0, 0xfffe9841, 0xffffb509, 0xffffa139, 0xffff918d, 0xffff86b5, 0xffff812a, 0xffff812a, 0xffff86b5, 0xffff918d, 0xffffa139, 0xffffb509, 0xfffe9841, 0xfffd95f0, 0xfffd95f0};
static int numpoints = 31;
static ffloat h = 0xfffe6b3b;
static ffloat hinv = 0x00034c64;
static ffloat pi2=0x00036487;
static ffloat pi2inv=0xfffe517c;
if(FFlt(xin,xlo)){
x=FFadd(
xin,
FFmult(
S16int2FFloat(
FFloatTrunc2S16int(
FFmult(
FFsub(xhi,xin),
pi2inv
)
)
),
pi2
)
);
}else if(FFgt(xin,xhi)){
x=FFsub(
xin,
FFmult(
S16int2FFloat(
FFloatTrunc2S16int(
FFmult(
FFsub(xin,xlo),
pi2inv
)
)
),
pi2
)
);
}
klo = FFloatTrunc2S16int(FFmult(FFsub(x,xlo),hinv));
khi=klo+1;
xdiff0 = FFsub(x, FFadd(xlo, FFmult(h,S16int2FFloat(klo))));
xdiff1 = FFsub(xdiff0, h);
return ( FFadd(ya[klo], FFadd(FFmult(FFmult(FFsub(ya[khi],ya[klo]), hinv), xdiff0), FFmult(FFmult(y2a[khi], xdiff0), xdiff1))) );
}
GPIO library
//---------------------------------------------------------
// start of header file (gpio.h)
//---------------------------------------------------------
#if !defined(_GPIO_H_)
#define _GPIO_H_
typedef unsigned long dword;
typedef struct tGPIOpinTag
{
dword dwReg;
dword dwClr;
dword dwSet;
int iBit;
dword dwFunction;
} tGPIOpin;
#define REG32 volatile dword *
//
// bit patterns for alternate pin functions.
//
#define PINFUNC_GPIO ( 0x00000000 )
#define PINFUNC_ALT1 ( 0x55555555 )
#define PINFUNC_ALT2 ( 0xAAAAAAAA )
#define PINFUNC_ALT3 ( 0xFFFFFFFF )
//
// Active high and low works by swapping the SET and CLR register offsets round
//
#define GPIO_ACTIVE_L FIO_SET_OFS, FIO_CLR_OFS
#define GPIO_ACTIVE_H FIO_CLR_OFS, FIO_SET_OFS
//
// Start addresses of GPIO blocks of registers
//
#define LPC_GPIO_BASE ( 0x2009C000UL )
#define LPC_GPIO0_BASE ( LPC_GPIO_BASE + 0x00000 )
#define LPC_GPIO1_BASE ( LPC_GPIO_BASE + 0x00020 )
#define LPC_GPIO2_BASE ( LPC_GPIO_BASE + 0x00040 )
#define LPC_GPIO3_BASE ( LPC_GPIO_BASE + 0x00060 )
#define LPC_GPIO4_BASE ( LPC_GPIO_BASE + 0x00080 )
//
// Offsets to the direction register and PIN register
//
#define FIO_SET_OFS ( 0x00000018 )
#define FIO_CLR_OFS ( 0x0000001C )
#define FIO_DIR_OFS ( 0x00000000 )
#define FIO_PIN_OFS ( 0x00000014 )
#define FIO_MASK_OFS ( 0x00000010 )
// Parameters for vGPIODDsetDirection
#define PIN_IN ( FALSE )
#define PIN_OUT ( TRUE )
//
// Macro for pin definition structure
//
#ifdef _INSIDE_GPIODD_
//
// this version is for use inside the gpio module
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
const tGPIOpin t##name = { \
LPC_GPIO##port##_BASE, \
GPIO_ACTIVE_##act, \
bit, \
PINFUNC_##func \
}; \
const tGPIOpin * const name = &t##name;
#else
//
// and this is how external modules see the pin definition
//
#define PINFUNC_DEF( name, port, bit, act, func ) \
extern const tGPIOpin * const name;
#endif
//
// include the hardware pin allocations from another file
// (see example below)
//
#include "gpio_pindefs.h"
extern void vGPIODDsetPinFunction( const tGPIOpin * const psPin );
extern void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput );
extern void vGPIODDsetActive( const tGPIOpin * const psPin );
extern void vGPIODDsetInactive( const tGPIOpin * const psPin );
extern bool boGPIODDgetPin( const tGPIOpin * const psPin );
#endif // _GPIO_H_
//---------------------------------------------------------
// end of header file (gpio.h)
//---------------------------------------------------------
//---------------------------------------------------------
// start of example gpio_pindefs.h
//---------------------------------------------------------
#if !defined(_GPIO_PINDEFS_H_)
#define _GPIO_PINDEFS_H_
// LEDs
PINFUNC_DEF( GPIO_LED_GREEN, 1, 25, L, GPIO )
// USB interface
PINFUNC_DEF( GPIO_USB_VBUS, 1, 30, H, ALT1 )
PINFUNC_DEF( GPIO_USB_CONNECT, 2, 9, L, ALT1 )
// Serial Ports
PINFUNC_DEF( UART0_RX, 0, 3, H, ALT1 )
PINFUNC_DEF( UART0_TX, 0, 2, H, ALT1 )
PINFUNC_DEF( UART1_RX, 0, 16, H, ALT1 )
PINFUNC_DEF( UART1_TX, 0, 15, H, ALT1 )
// SPI port
PINFUNC_DEF( SPI_MOSI, 0, 9, H, ALT2 )
PINFUNC_DEF( SPI_MISO, 0, 8, H, ALT2 )
PINFUNC_DEF( SPI_SCK, 0, 7, H, ALT2 )
PINFUNC_DEF( SPI_SSEL, 0, 6, L, ALT2 )
#endif // _GPIO_PINDEFS_H_
//---------------------------------------------------------
// end of example gpio_pindefs.h
//---------------------------------------------------------
//---------------------------------------------------------
// start of gpio.c
//---------------------------------------------------------
#define _INSIDE_GPIODD_ ( 1 )
#include "gpio.h"
/* --------------------------------------------------------
vGPIODDsetPinFunction
........................................................
Description : Set the pin connect block from a pin
definition
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinFunction( const tGPIOpin * const psPin )
{
if ( psPin )
{
// Each PINSELXX register contains the settings
// for 16 port pins. Each PINSEL register is 4 bytes
// above the previous one. Base addresses for ports
// are 32 bytes apart.
dword dwPinSel = LPC_PINCON_BASE +
((psPin->dwReg - LPC_GPIO0_BASE) / 4) +
((psPin->iBit / 16) * 4);
dword dwMask = ( 0x00000003 << ( 2 * ( psPin->iBit % 16 ) ) );
REG32 pdwPinSel = (REG32)dwPinSel;
*pdwPinSel = ( *pdwPinSel & ~dwMask ) |
( psPin->dwFunction & dwMask );
}
}
/* --------------------------------------------------------
vGPIODDsetPinDirection
........................................................
Description : Sets the pin direction from a pin
definition
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetPinDirection( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
if( boOutput )
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) |= ( 1 << psPin->iBit );
}
else
{
(*((REG32) (psPin->dwReg + FIO_DIR_OFS))) &= ~( 1 << psPin->iBit );
}
}
}
/* --------------------------------------------------------
vGPIODDconfigurePin
........................................................
Description : Combination function to configure and set
direction of GPIO pin
Params : psPin - pin definition
boOutput - set to TRUE to turn the pin into an
output
Returns : Nothing
----------------------------------------------------- */
void vGPIODDconfigurePin( const tGPIOpin * const psPin,
const bool boOutput )
{
if ( psPin )
{
vGPIODDsetInactive( psPin );
vGPIODDsetPinFunction( psPin );
vGPIODDsetPinDirection( psPin, boOutput );
}
}
/* --------------------------------------------------------
vGPIODDsetActive
........................................................
Description : Sets a pin to its active state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetActive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Set register to set a single bit
(*((REG32) (psPin->dwReg + psPin->dwSet))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
vGPIODDsetInactive
........................................................
Description : Sets a pin to its inactive state
Params : psPin - pin definition
Returns : Nothing
----------------------------------------------------- */
void vGPIODDsetInactive( const tGPIOpin * const psPin )
{
if ( psPin )
{
// use the Clr register to clear a single bit
(*((REG32) (psPin->dwReg + psPin->dwClr))) = ( 1 << psPin->iBit );
}
}
/* --------------------------------------------------------
boGPIODDgetPin
........................................................
Description : Gets the current state of a pin
Params : psPin - pin definition
Returns : TRUE if the pin is in its active state,
FALSE otherwise.
----------------------------------------------------- */
bool boGPIODDgetPin( const tGPIOpin * const psPin )
{
if ( psPin )
{
dword dwPins = *((REG32) (psPin->dwReg + FIO_PIN_OFS));
if ( psPin->dwSet > psPin->dwClr )
{
dwPins = ~dwPins;
}
return ((dwPins & ( 1 << psPin->iBit )) != 0 );
}
else
{
return FALSE;
}
}
//---------------------------------------------------------
// end of gpio.c
//---------------------------------------------------------
MSP430 SPI-Master IO without interrupt
/**
* @file SPI.h
* Control's for the SPI
*/
#ifndef FILE_SPI_H
#define FILE_SPI_H
class SPI
{
public:
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
static void _Init(void);
/**
* @brief Send data to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_DataOut(unsigned char msg);
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
static void LCD_DataOut(char *msg, int Length);
/**
* @brief Send command to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_CommOut(unsigned char msg);
private:
typedef enum {ModeIdle, ModeLCD, ModeMem} SPI_Modes;
static SPI_Modes SPI_Mode;
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
static void ConfigSPI(SPI_Modes Mode);
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
static void DoSPI_IO(char* TX, char* RX, int IOcount);
};
#############################################
/**
* @file SPI.c
* Control's for the SPI
*/
#include "SPI.h"
#include "msp430.h"
#define ArrayLength(array) (sizeof(array)/sizeof(array[0]))
/// Macro to set a bit y in variable x
#define SETB(x,y) (x |= (1 << y))
/// Macro to reset a bit y in variable x
#define CLRB(x,y) (x &= ~(1 << y))
SPI::SPI_Modes SPI::SPI_Mode;
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
void SPI::_Init(void)
{
SPI_Mode = ModeIdle;
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_DataOut(unsigned char msg) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
void SPI::LCD_DataOut(char *msg, int Length) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
DoSPI_IO(msg, 0, Length);
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send command to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_CommOut(unsigned char msg) //Command Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
CLRB(P2OUT,7); //A0 = Command, A0 = 0
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS = 1
}
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
void SPI::ConfigSPI(SPI_Modes Mode)
{
if(SPI_Mode == Mode)
return;
switch(Mode)
{
case ModeLCD:
/*******************************************************
* USCI - SPI configuration for LCD *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x03; // SPI Clk = SMCLK / 3 = 1 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeMem:
/*******************************************************
* USCI - SPI configuration for Memory *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x01; // SPI Clk = SMCLK / 1 = 3 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeIdle:
default:
Mode = ModeIdle;
break;
}
SPI_Mode = Mode;
}
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
void SPI::DoSPI_IO(char* TX, char* RX, int IOcount)
{
volatile int dummy = 0x81;
if((TX == 0) && (RX == 0)) return;
while(IOcount > 0)
{
if(UCB0IFG & UCTXIFG)
{
if(TX == 0)
UCB0TXBUF = dummy; // dummy write
else
{
UCB0TXBUF = *TX++;
IOcount--;
}
}
if(UCB0IFG & UCRXIFG)
{
if(RX == 0)
dummy = UCB0RXBUF; // dummy read
else
{
*RX++ = UCB0RXBUF;
IOcount--;
}
}
}
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
dummy = UCB0RXBUF; // dummy read to empty any remaining data in RX buffer
}
high resolution frequency counter implementation
/* high resolution frequency counter implementation
*/
/* timer2 interrupt handler. timer1 is an extended
32 bits register (16 bits hard + 16 softs)
incremented once per:
1 / (fcpu / prescal) <=> prescal / fcpu
thus, it will overflow at:
2^16 * prescal / fcpu
on tim2 overflow, the interrupt handler is called
and stores the tim1 current value in tim1_cur_counter.
thus, the tim1 value integrated over the whole
tim1 period is:
(tim1_ovf_counter * 2^16) + tim1_cur_counter.
tim2_is_ovf is set to notify the application.
*/
static volatile uint8_t tim2_ovf_counter;
static volatile uint8_t tim2_is_ovf;
static volatile uint16_t tim1_cur_counter;
ISR(TIMER2_OVF_vect)
{
if ((tim2_ovf_counter--) == 0)
{
/* disable tim1 before reading */
TCCR1B = 0;
tim1_cur_counter = TCNT1;
/* disable tim2 */
TCCR2B = 0;
tim2_is_ovf = 1;
}
}
/* timer2 interrupt handler. timer2 is a 8 bits counter
incremented by the input signal rising edges. since
8 bits are not enough to integrate, an auxiliary
register (tim2_ovf_counter) is updated on overflow.
tim2_ovf_counter is an 8 bits register, and will
overflow without any notice past 0xff.
*/
static volatile uint8_t tim1_ovf_counter;
ISR(TIMER1_OVF_vect)
{
++tim1_ovf_counter;
}
static void hfc_start(void)
{
/* resolution: 1.907349 hz per tick */
/* fmax: 500 khz */
/* acquisition time: 0.524288 seconds */
/* disable interrupts */
TIMSK1 = 0;
TIMSK2 = 0;
/* reset stuff */
tim1_ovf_counter = 0;
tim1_cur_counter = 0;
tim2_is_ovf = 0;
/* 0x100 overflows make 16 bits */
tim2_ovf_counter = 0xff;
/* configure tim2
normal operation
prescaler 128
enable interrupt on overflow
*/
TCNT2 = 0;
TIMSK2 = 1 << 0;
TCCR2A = 0;
TCCR2B = 0;
/* configure tim1
t1 pin (pd5) rising edge as external clock
*/
DDRD &= ~(1 << 5);
TCNT1 = 0;
TIMSK1 = 1 << 0;
TCCR1A = 0;
TCCR1B = 0;
/* start tim1, tim2 */
TCCR1B = 7 << 0;
TCCR2B = 5 << 0;
}
static uint8_t hfc_poll(void)
{
return tim2_is_ovf;
}
static uint32_t hfc_wait(void)
{
/* busy wait for tim1 to overflow. returns the resulting
16 bits counter, to be multiplied by the frequency
resolution (refer to hfc_start) to get the actual
frequency.
*/
/* force inline, do not use hfc_poll */
while (tim2_is_ovf == 0) ;
return ((uint32_t)tim1_ovf_counter << 16) | (uint32_t)tim1_cur_counter;
}
static inline uint32_t hfc_start_wait(void)
{
hfc_start();
return hfc_wait();
}
static inline double hfc_to_hz(uint32_t counter)
{
return 1.907349 * (double)counter;
}
Playing sound in DAC using simple 8051 MCU
/*System reads wav files by SPI from external memory . Samples read are sent to external DAC by other SPI to be played. It's nedeed ISR reception (not included) of SPI to manage info of this file. At the beginnig, this timing is not important, but after all info of wav file is read, timming is fitted to sampling time of wav to play.
This Timer ISR manages read samples by SPI_Memory and write in SPI_DAC in 8051 MCU. Because this MCU has only one SPI,the info transmited to DAC is managed by simple GPIOs */
void Timer2_ISR (void) interrupt 5
{
char desp=0;
char temp=0;
SFRPAGE_save = SFRPAGE;
//! buffer to store 1 or 0 in bit content audio to convert
if(TF2H == 1)
{
/*When system starts, only reads from memory, to get wav header (sampletime, length, and because
there are more than one wav file in memory, the starting address of wav, In "configurating" the
timer period is not sampleTime*/
if (configurating==TRUE)
{
SPI_Read_Memory(); /*it's nedeed ISR to manage recepcion*/
}
else
{
/*pread counts samples of wav file reading*/
if (pread<(audioLength+1))
{
/*wavSampleRead is the last sample stored by SPI, taken in SPI ISR*/
PCA0CPH0=wavSampleRead;
desp=4;
MOSI_SPI_SW=0;
index++;
if (index==256)
{
index=0;
}
CS_DAC=0; /*Chip Select of DAC. This SPI is controlled by GPIOs*/
while (desp!=0)
{
CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
desp=0;
while (desp!=8)
{
CLK_SPI_SW=0;
if ((wavSampleRead&0x80)!=0)
{
MOSI_SPI_SW=1;
}
else
{
MOSI_SPI_SW=0;
}
CLK_SPI_SW=1;
desp++;
wavSampleRead=wavSampleRead<<1;
}
CLK_SPI_SW=0;
MOSI_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CLK_SPI_SW=1;
CLK_SPI_SW=0;
CS_DAC=1;
MOSI_SPI_SW=0;
/* starts new transmision on SPI to read new sample from memory*/
SFRPAGE = ACTIVE_PAGE;
SPI_transferData = NO_OK;
SPI0DAT = TRANSFER_MEMORY_COMMAND;
SFRPAGE = SFRPAGE_save;
buffer_Index=0;
pread++;
}
else
{
/*in configurating mode is stored a buffer with some samples. This buffer
it's used to allow "clac" noises to reproduce the audioagain (becuase the audio is
playing periodically. The audios are siren sounds, and the last sample must linked whit
the first sample, having a compled wave form)*/
PCA0CPH0=buffer[buffer_Index];
temp=buffer[buffer_Index];
buffer_Index++;
if (buffer_Index==1)
{
looping=1;
}
else if (buffer_Index==BUFFER_SIZE)
{
pread=BUFFER_SIZE+1;
}
desp=4;
MOSI_SPI_SW=0;
CS_DAC=0;
while (desp!=0)
{
CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
desp=0;
while (desp!=8)
{
CLK_SPI_SW=0;
if ((temp&0x80)!=0)
{
MOSI_SPI_SW=1;
}
else
{
MOSI_SPI_SW=0;
}
//CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp++;
temp=temp<<1;
}
desp=4;
while (desp!=0)
{
CLK_SPI_SW=0;
MOSI_SPI_SW=0;
//CLK_SPI_SW=0;
CLK_SPI_SW=1;
desp--;
}
CLK_SPI_SW=0;
CS_DAC=1;
MOSI_SPI_SW=0;
CS_DAC=1;
}
if (pread==BUFFER_SIZE+1)
{
/*First sample to begin the cicle*/
SFRPAGE = ACTIVE_PAGE;
SPI_transferData = NO_OK;
SPI0DAT = TRANSFER_MEMORY_COMMAND;
SFRPAGE = SFRPAGE_save;
}
}
}
TF2H = 0;
}
}
Fast lookup plus interpolation computation of non-linear functions
// Fast integer arithmetic lookup+interpolation method for converting
// barometric pressure readings to altitude readings.
// Each Lookup Table (LUT) entry is the altitude in centimeters above
// sea level, corresponding to an implicit pressure value,
// calculated as [PA_INIT - 1024*LUTindex] in Pascals.
// The region of interest is approximately 460metres below sea level,
// to 10000 metres above sea level.
typedef signed long s32;
#define PZLUT_ENTRIES 80
#define PA_INIT 106956L
#define PA_DELTA 1024L
#define Z_LIMIT_LO -99999L
#define Z_LIMIT_HI 99999L
const s32 gPZTbl[PZLUT_ENTRIES] = {
-45853,
-37662,
-29407,
-21087,
-12700,
-4245,
4279,
12874,
21540,
30279,
... // values removed for brevity
959708,
984147,
1009345
};
// Calculates the altitude in centimeters above sea level, given the barometric
// sensor pressure reading in pascals. The nearest lower LUT index is computed.
// The altitude is then linearly interpolated from the corresponding altitude
// values at the lower and next higher LUT index. Computation is optimized by
// ensuring the difference between LUT entries are spaced by a power of 2, in
// this case 2^10 (1024), so no integer division is required.
// Returns the error values Z_LIMIT_LO or Z_LIMIT_HI if
// the pressure data exceeds the LUT index limits.
s32 sns_Pa2Cm(s32 pa) {
s32 inx,pa1,z1,z2,z;
if (pa > PA_INIT) {
z = Z_LIMIT_LO;
}
else {
inx = (PA_INIT - pa)>>10;
if (inx >= PZLUT_ENTRIES-1) {
z = Z_LIMIT_HI;
}
else {
pa1 = PA_INIT - (inx<<10);
z1 = gPZTbl[inx];
z2 = gPZTbl[inx+1];
z = z1 + (((pa1-pa)*(z2-z1))>>10);
}
}
return z;
}
Linear regression of samples in a circular buffer
// Linear regression of samples in a circular sample
// buffer. Uses only integer arithmetic, optimized for
// computation on 16bit microcontroller with hardware
// multiplier. The linear regression computation is
// simplified considerably by subtracting out the rolling
// average of the buffer samples.
// This computation assumes the samples arrive at
// regular intervals, and this sampling rate is known.
// Usage :
// 1. call lr_Init() to initialize gnLRDenominator,
// gnNumSamples and gnSampleIndex
// 2. get first sample value and initialize gZBuffer
// with this value
// 3. for each subsequent incoming sample
// gZBuffer[gnSampleIndex] = lr_GetNewZSample();
// gZAverage = lr_CalculateAverage(gZBuffer,gnNumSamples);
// gSlope = lr_CalculateSlope(gZBuffer, gnNumSamples, gnSampleIndex, gZAverage);
// gnSampleIndex++;
// if (gnSampleIndex >= gnNumSamples) gnSampleIndex = 0;
//
typedef signed long s32;
#define MAX_Z_SAMPLES 80
#define SENSOR_SAMPLES_PER_SEC 26L
#define MAX_SLOPE 2000L
#define CLAMP(x,min,max) {if ((x) <= (min)) (x) = (min); else if ((x) >= (max)) (x) = (max);}
s32 gnLRDenominator;
int gnSampleIndex, gnNumSamples;
s32 gZBuffer[MAX_Z_SAMPLES];
s32 gZAverage;
s32 gSlope;
void lr_Init(int numSamples) {
s32 zSample, sumT, sumT2;
int inx;
sumT = -(numSamples * (numSamples-1L))/2L;
sumT2 = (numSamples * (numSamples-1L)*(2L*numSamples-1L))/6L;
gnLRDenominator = (numSamples*sumT2) - (sumT*sumT);
gnSampleIndex = 0;
gnNumSamples = numSamples;
zSample = lr_GetNewZSample(); // get a sample from the sensor
inx = gnNumSamples;
while (inx--) gZBuffer[inx] = zSample; // fill the ZBuffer with first sample value
}
s32 lr_CalculateAverage(s32* pZBuffer, int numSamples ) {
int inx;
s32 accumulator, average;
inx = numSamples;
accumulator = 0;
while (inx--) {
accumulator += pZBuffer[inx];
}
accumulator = (accumulator >= 0 ? accumulator +numSamples/2 : accumulator - numSamples/2);
average = accumulator/numSamples; // rounded up average
return average;
}
/// Linear regression of samples in buffer to calculate slope.
s32 lr_CalculateSlope(s32* pZBuffer, int numSamples, int currentSampleIndex, int zAverage) {
int inx,tRelative;
s32 z, sumZT,slope;
sumZT = 0;
inx = numSamples;
while (inx--) {
z = pZBuffer[inx] - zAverage; // subtract out the average value to simplify the arithmetic
tRelative = inx - currentSampleIndex; // time origin is the current sample in window
if (tRelative > 0) {
tRelative -= numSamples;
}
sumZT += ((s32)tRelative*z);
}
slope = (sumZT*(s32)(SENSOR_SAMPLES_PER_SEC*numSamples))/gnLRDenominator;
CLAMP(slope,-MAX_SLOPE,MAX_SLOPE);
return slope;
}