PID (Floating Point)
/*! \details This structure holds the data to run a
* floating point PID loop.
*/
typedef struct{
float max /*! \brief Max manipulated value */;
float min /*! \brief Miniumum manipulated value */;
float e /*! \brief Error value */;
float i /*! \brief Integrator value */;
float kp /*! \brief Proportional constant */;
float ki /*! \brief Integrator constant */;
float kd /*! \brief Differential constant */;
} pid_f_t;
/*! \details This function initializes the data in a PID structure.
*
*/
void pid_init_f(pid_f_t * ptr /*! A pointer to the PID data structure */,
float min /*! The manipulated variable's minimum value */,
float max /*! The manipulated variable's maximum value */){
memset(ptr, 0, sizeof(pid_f_t));
ptr->min = min;
ptr->max = max;
}
/*! \details This function updates the value of the manipulated variable (MV)
* based on the current state of the PID loop.
*/
float pid_update_f(float sp /*! The set point */,
float pv /*! The process variable */,
pid_f_t * ptr /*! A pointer to the PID constants */){
float temp;
float e;
float p;
float manp;
float tmpi;
//get the error from the last call
e = ptr->e;
//calculate the new error (set point - present value)
ptr->e = sp - pv;
//use a temp variable for the integrator
tmpi = ptr->i + ptr->e;
//update the manipulated process variable
manp = ptr->kp * ptr->e + ptr->ki * tmpi + ptr->kd * (ptr->e - e);
//the integrator is only updated if the manipulated process is within range
//otherwise the system will likely become unstable
if ( (manp < ptr->max) && (manp > ptr->min) ){
ptr->i = tmpi;
} else if ( manp > ptr->max ){
manp = ptr->max;
} else if ( manp < ptr->min ){
manp = ptr->min;
}
return manp;
}
Macros to get and set a bit field within a value
// Get a bit field from a value
#define GetField(Var, Mask, Shift) \
(((Var) >> (Shift)) & (Mask))
// Set a bit field in a value
#define SetField(Var, Mask, Shift, Val) \
(Var) = (((Var) & ~((Mask) << (Shift))) | (((Val) & (Mask)) << (Shift)))
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 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))) );
}
Software UART receiver
/**
* @file
* Software serial (UART) receiver
*
* This module implements the receive engine for asynchronous serial
* communications using polling ("bit banging"). Transmission capability
* is not provided.
*
* The data format is <tt>8-N-1</tt>:
* - Eight data bits
* - No parity
* - One stop bit
*
* <h2>Structural overview</h2>
* The receiver is implemented as a polled finite state machine. The state
* of the I/O pin is passed as an argument to the state machine animation
* function <code>soft_uart_rx()</code>. The polling function must be called
* on a stable timebase at a frequency at least three times
* the bit rate. The function returns a flag to indicate that a character has
* been received and places the received character in a fixed buffer.
*
* <h2>Timing</h2>
* The baud rate of the transmitter constrains the ossortment of possible
* interrupt rates. However, this receiver is designed to be configurable so
* as to maximize those choices.
*
* Any frequency multiple of at least 3 is suitable. Is this example, the
* sample rate is four times the serial data bit rate:
*
* <pre>
* Given
* =====
* Baud rate specification: 1200 +/- 4%
* System interrupt rate: 5 kHz (200 us)
*
* Selecting a sample rate
* =======================
* Chosen multiplier: samples per bit
* Sample rate: 5 kHz / 4 == 1250 baud (4.16% high)
* </pre>
*
* Since the baud rate is high in this example, We will have a tendency to
* sample earlier and earlier on each successive bit. Therefore it is desirable
* to sample slightly later in the bit time if possible.
* <pre>
* \#define SOFT_SOFT_UART_RX_BIT_TIME 5
* \#define SOFT_UART_RX_START_SAMPLES 2
* </pre>
* The diagram below shows the resultant timing. The actual bit times are 4%
* slower, owing to the fact that the system interrupy is not an exact multiple
* of the bit time.
*
* The sample timing error at the stop bit is (4% X 9) = 36% too early.
* <pre>
* _______ _______________ _______________
* \\_______________/ \\...________________/
* +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
* | Cycle | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | 8 | 9 | A | B | C | D | E | F |
* +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
* | Data | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
* | | Start bit | Data bit 0 | | Data bit N | Stop bit |
* | Samp. | X | X | | | | | X | | | | | X | | | | X | |
* +-------+---+---+---+---+---+---+---+---+...+---+---+---+---+---+---+---+---+
* ^ ^ |<------------->|
* | | |
* | | SOFT_UART_RX_BIT_TIME -------+
* | |
* +---+---- SOFT_UART_RX_START_SAMPLES
* </pre>
* Here is an explanation of how a character is received:
* -# We sample the line continuously until the START (logic zero) bit is seen.
* -# Just to make sure it wasn't noise, we sample the line a second (or third
* or fourth, depending on the setting) time with the expectation that the
* state hasn't changed.
* -# We continue to sample the start bit until we have reached the center of
* the bit time. The line must stay in the low state. This shifts us to
* safety away from edges.
* -# We delay (frequency multiplier) cycles, ignoring the state of the line.
* This puts us in the middle of the first data bit.
* -# We sample and save the data bit, then wait (frequency multiplier - 1)
* cycles.
* -# We repeat until we have sampled all data (payload) bits. The last bit
* is sampled and must be a logic one.
*
* <h2>Limitations</h2>
* For speed, the receive buffer is implemented as a global variable that is
* to be accessed directly by the calling code. Also, the state variable
* is private to this module. Therefore, only one instance of the soft
* UART receiver is supported in a given project.
*
* @author Justin Dobbs
*/
#include <stdbool.h>
/** The number of times to sample the start bit.
This defines the phase shift of subsequent samples. If the interrupt rate is
a bit high relative to the baud rate, we want to sample late to
minimize cumulative timing error. */
#define SOFT_UART_RX_START_SAMPLES 3
/** The inter-bit delay time, a.k.a. the frequency multiplier */
#define SOFT_UART_RX_BIT_TIME 4
/* State definitions */
static bool st_idle (bool);
static bool st_start_bit (bool);
static bool st_delay_rx0 (bool);
static bool st_delay_rx1 (bool);
static bool st_delay_rx2 (bool);
static bool st_delay_rx3 (bool);
static bool st_delay_rx4 (bool);
static bool st_delay_rx5 (bool);
static bool st_delay_rx6 (bool);
static bool st_delay_rx7 (bool);
static bool st_delay_stop (bool);
static bool st_abort_wait_for_idle (bool);
/**
* Soft UART receiver polling function.
*
* This function implements the receiver. It should be called on a stable
* timebase at a fixed multiple of the bit rate.
*
* @note This is implemented as a pointer to a function to handle the current
* state. The caller need only invoke the function using the pointer.
*
* @param[in] x the state of the input line:
* - <code>true</code>: the line is high
* - <code>false</code>: the line is low
*
* @retval true if a character is ready in <code>soft_uart_rx_buf</code>
* @retval false otherwise
*/
bool (*soft_uart_rx)(bool) = st_idle;
/** Serial recieve buffer. This should be immediately read after
<code>soft_uart_rx()</code> returns <code>true</code>. */
unsigned char soft_uart_rx_buf;
/** Cycle counter, for timing. */
static unsigned char i;
/**
* Sampling continuously, waiting for the start bit.
*/
static bool st_idle (bool x)
{
if (!x)
{
i = SOFT_UART_RX_START_SAMPLES - 1;
soft_uart_rx = st_start_bit;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Sampling the start bit a few more times to make sure it's solid. This also
* provides time offset for sampling future bits in the middle of the bit time.
*/
static bool st_start_bit (bool x)
{
/* Reject if the start bit does not last long enough */
if (x)
{
soft_uart_rx = st_idle;
}
else if (--i == 0)
{
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx_buf = 0;
soft_uart_rx = st_delay_rx0;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling the LSb (bit 0).
*/
static bool st_delay_rx0 (bool x)
{
/* When it's time, shift in the data to the RX buffer. If we have
received all the data, go wait for the STOP bit. */
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x01;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx1;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 1.
*/
static bool st_delay_rx1 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x02;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx2;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 2.
*/
static bool st_delay_rx2 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x04;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx3;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 3.
*/
static bool st_delay_rx3 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x08;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx4;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 4.
*/
static bool st_delay_rx4 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x10;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx5;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 5.
*/
static bool st_delay_rx5 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x20;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx6;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 6.
*/
static bool st_delay_rx6 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x40;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_rx7;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling bit 7.
*/
static bool st_delay_rx7 (bool x)
{
if (--i == 0)
{
if (x)
{
soft_uart_rx_buf |= 0x80;
}
i = SOFT_UART_RX_BIT_TIME;
soft_uart_rx = st_delay_stop;
}
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Waiting one bit time, then sampling the stop bit.
* @note The reception is aborted if the stop bit does not arrive on schedule.
*/
static bool st_delay_stop (bool x)
{
if (--i == 0)
{
/* STOP bit is always logic ONE by definition */
if (x)
{
soft_uart_rx = st_idle;
return true; /* Got a character */
}
else
{
/* Stop bit didn't happen when we expected it. Go sit and wait
indefinitely for the line to go high. */
soft_uart_rx = st_abort_wait_for_idle;
return false;
}
}
/* Haven't sampled the stop bit yet! */
return false;
}
/* -------------------------------------------------------------------------- */
/**
* Reception aborted; waiting as long as required for the line to idle high
* again.
*/
static bool st_abort_wait_for_idle (bool x)
{
/* NOW the line is finally high/idle again. Start the receive process over.
We did not get a character. */
if (x)
{
soft_uart_rx = st_idle;
}
return false;
}
/* Header file */
#if !defined(_SOFT_UART_RX_H)
#define _SOFT_UART_RX_H
/**
* @file
* Soft UART receiver header file
*
* This file implements the interface to the software UART reciever module.
* The full documentation is located in @ref soft_uart_rx.c.
*
* @author Justin Dobbs
*/
#include <stdbool.h>
/* Actually a function pointer, but this is supposed to be opaque. This is
called from a periodic interrupt.
@param[in] x the state of the serial line (true == high) */
extern bool (*soft_uart_rx) (bool x);
/* The receive buffer */
extern unsigned char soft_uart_rx_buf;
#endif
LED Blinker Using a Timer/Counter
/**@file timer_blinker.c
@brief A more advanced LED blinker using a timer
@author Stephen Friederichs
@date 3/28/13
@note This code assumes that the LED is active high (pin sources current)
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((0x00 == ((x & (1<<y))>> y))?0x00:0x01)
#define TOGGLE(x,y) (x ^= (1<<y))
int main(void)
{
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* TCCR1A - ATMega328 Datasheet Section 16.11.1 pg 132
No waveform generation is required on this timer, so set all
ports to normal operation
*/
TCCR1A = 0x00;
/* TCCR1C - ATMega328 Datasheet Section 16.11.3 pg 135
This register is only used for output compare.
There's no output compare in this application so this can be all 0's
*/
TCCR1C = 0x00;
/* TCCR1B
Note: I've disabled the CKDIV8 fuse so that the clock source is 8MHz
ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1A
No input capture used - bits 7:6 are 0
No waveform generation used - bits 4:3 are 0
Clock source select is bits 2:0 but are not yet set - wait until the
main loop is ready to start
As per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer
to Normal mode causes the counter to count up until it reaches 0xFFFF
at which point it will overrun and start back at 0. To configure this
timer/counter to produce a period of 500ms we need to start counting
at a value that causes it to reach 65535 in 500ms.
What is that value?
With a clock prescaler of 256 each count of the timer is roughly
(1/8MHz)*256 = 32uS
500ms / 32us /tick = 15625 ticks /500ms
The counter counts up to 65535, so to determine what value we have to
start at we subtract 15635 from 65536:
65536-15625 = 49910
*/
#define TIMER1_PERIOD 49910
TCNT1 = TIMER1_PERIOD;
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
/* Start the timer/counter
ATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1B
No Waveform generation: bits 4:3 = 0
No input capture: bits 7:6 = 0
Clock select: ClkIO/256 - bits 2:0 = 100b = 0x04
*/
TCCR1B = 0x04; //This starts the counter/timer
while(1)
{
/* Handle the Heartbeat LED
When the timer/counter reaches 65535 the 500ms period will have
elapsed and TIFR1 bit 1 will be '1'
*/
if(READ(TIFR1,0))
{
/* ATMega328 Datasheet Section 16.11.9 pg137
Setting TIFR1 bit 1 clears the overflow flag
*/
SET(TIFR1,0);
/* Toggle the LED to flash it at 1Hz*/
TOGGLE(PORTD,7);
/* Reload the timer/counter count value to the previous value
so that the period remains the same
*/
TCNT1 = TIMER1_PERIOD;
}
/* Now you can do useful work here - no delay loops!*/
}
}
PGA117 driver
#define READ 0x6A00
#define WRITE 0x2A00
#define NOP WRITE 0x0000
#define SDN_DIS 0xE100
#define SDN_EN 0xE1F1
#define GAIN_1 0
#define GAIN_2 1
#define GAIN_4 2
#define GAIN_8 3
#define GAIN_16 4
#define GAIN_32 5
#define GAIN_64 6
#define GAIN_128 7
#define CS BIT0
#define DI BIT1
#define DO BIT2
void write_pga(unsigned int value);
void set_ch_gain(unsigned int ch,unsigned int gain);
void config_spi();
void config_spi()
{
P1DIR |= 0x01; // P1.0 output
P3SEL |= 0x0C; // P3.2,3 USCI_B0 option select
P3DIR |= 0x01; // P3.0 output direction
UCB0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI mstr, MSB 1st
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 = 0x02;
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
}
void write_spi(char data)
{
UCB0TXBUF = data; // Byte to SPI TXBUF
while (!(IFG2 & UCB0TXIFG)); // USCI_A0 TX buffer ready?
}
void write_pga(unsigned int value)
{
P3OUT &= ~CS;
write_spi(value>>8);
write_spi(value);
P3OUT |= CS;
}
void set_ch_gain(unsigned int ch,unsigned int gain)
{
unsigned int command;
command = gain<<4;
command += ch;
command +=WRITE;
write_pga(command);
}
Interfacing ADS7807
#define sclk PIN_D3
#define sdata PIN_D4
#define rc PIN_D5
#define busy PIN_D6
#define cs PIN_C5
void init_ads7807()
{
output_low(sclk);
output_high(rc);
delay_us(2);
output_high(cs);
}
int32 read_ads7807()
{
BYTE i;
int32 adc_result=0;
while(!input(busy));
output_low(rc);
delay_cycles(1);
output_low(cs);
delay_us(1);
output_high(cs);
delay_cycles(1);
output_high(rc);
while(!input(busy));
output_low(cs);
for(i=1;i<=16;++i)
{
output_high(sclk);
shift_left(&adc_result,4,input(sdata));
output_low(sclk);
}
output_high(cs);
adc_result*=7629;
return adc_result/10000;
}
Interfacing MAX6952
#define max_sdi PIN_C5
#define max_sdo PIN_C4
#define max_clk PIN_C3
#define max_cs PIN_C2
const int8 user_font[120]= {0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C,
0x77,0x6B,0x5D,0x6B,0X77,
0x1C,0x22,0x7F,0x22,0x1C};
#define config_addr 0x04
#define font_addr 0x05
#define test_addr 0x07
#define plane01_addr 0x20
#define plane02_addr 0x21
#define plane03_addr 0x22
#define plane04_addr 0x23
#define plane11_addr 0x40
#define plane12_addr 0x41
#define plane13_addr 0x42
#define plane14_addr 0x43
int8 config_byte;
void write_to_6952(int8 cmd,int8 data)
{
int8 i;
int16 ser_data;
ser_data=make16(cmd,data);
//shift_right(&ser_data,2,0);
output_low(max_clk);
output_low(max_cs);
for(i=1;i<=16;++i)
{
output_bit(max_sdi,shift_left(&ser_data,2,0));
output_high(max_clk);
delay_us(10);
// if(i<16)
output_low(max_clk);
//delay_us(6);
}
output_high(max_cs);
output_low(max_clk);
}
void write_user_font()
{
int8 j;
write_to_6952(font_addr,0x80);
for(j=0;j<120;j++)
{
write_to_6952(font_addr,user_font[j]);
}
}
/*******************************************************************
if state=1,normal operation
if state=0,shutdown
if wrt=1,write to 6952,otherwise update the config_byte register
*******************************************************************/
void shutdown(int1 state, int1 wrt)
{
if(state)
config_byte |= 0x01;
else
config_byte &= 0xFE;
if(wrt)
write_to_6952(config_addr,config_byte);
}
/*******************************************************************
if state=1,enable blinking
if state=0,disable blinking
if wrt=1,write to 6952,otherwise update the config_byte register
*******************************************************************/
void blink_enable(int1 state,int1 wrt )
{
if(state)
config_byte |= 8;
else
config_byte &= 0xF7;
if( wrt )
write_to_6952(config_addr,config_byte);
}
/*************************************************************************
if state=1,put the display in test mode
if state=0,normal mode
Does not affect plane data - original display is restored when set 0.
**************************************************************************/
void display_test(int1 state )
{
if(state)
write_to_6952(test_addr,1);
else
write_to_6952(test_addr,0);
}
soft Real Time Clock implementation
typedef struct t_smalltm{
u16 year;
u8 mon;
u8 day;
u8 hour;
u8 min;
u8 sec;
} t_smalltm;
t_smalltm rtc;
//**************************************************************
// call this function every 1 sec. from timer interrupt.
// for fast code execution rtc will be placed in internal RAM.
//**************************************************************
void realTimeClock(void)
{u8 rest;
if (++rtc.sec==60) // sec
{
rtc.sec=0;
if (++rtc.min==60) // min
{
rtc.min=0;
if (++rtc.hour==24) // hour
{
rtc.hour=0;
rtc.day++; // day
rest=rtc.year%4;
if ((((rest==0 && rtc.year%100!=0) || rtc.year%400==0)
&& rtc.mon==2 && rtc.day==30)
|| (rest && rtc.mon==2 && rtc.day==29)
|| ((rtc.mon==4 || rtc.mon==6 || rtc.mon==9 || rtc.mon==11)
&& rtc.day==31)
|| (rtc.day==32))
{
rtc.day=1;
if (++rtc.mon==13) // mon
rtc.mon=1, rtc.year++; // HAPPY NEW YEAR ! :)
}
}
}
}
}
//**************************************************************
// read RTC function
void getRTC(t_smalltm* stm)
{
disableInterrupts(); // evite erronated read
// because realTimeClock is called from interrupt
memcpy(stm,&rtc,sizeof(t_smalltm));
enableInterrupts();
}
//**************************************************************
// set RTC function
void setRTC(u16 year, u8 mon, u8 day, u8 hour, u8 min, u8 sec)
{
disableInterrupts();
rtc.year=year;
rtc.mon=mon;
rtc.day=day;
rtc.hour=hour;
rtc.min=min;
rtc.sec=sec;
enableInterrupts();
}
Additive White Gaussian Noise Generator
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.1415926536
double AWGN_generator()
{/* Generates additive white Gaussian Noise samples with zero mean and a standard deviation of 1. */
double temp1;
double temp2;
double result;
int p;
p = 1;
while( p > 0 )
{
temp2 = ( rand() / ( (double)RAND_MAX ) ); /* rand() function generates an
integer between 0 and RAND_MAX,
which is defined in stdlib.h.
*/
if ( temp2 == 0 )
{// temp2 is >= (RAND_MAX / 2)
p = 1;
}// end if
else
{// temp2 is < (RAND_MAX / 2)
p = -1;
}// end else
}// end while()
temp1 = cos( ( 2.0 * (double)PI ) * rand() / ( (double)RAND_MAX ) );
result = sqrt( -2.0 * log( temp2 ) ) * temp1;
return result; // return the generated random sample to the caller
}// end AWGN_generator()
Stepper motor controller for precise movement
/*
* IBM-PC Parallel Printer Port Data & Status Registers
* ====================================================
* 7 6 5 4 3 2 1 0 I/O Port
* +---+---+---+---+---+---+---+---+ ========
* Data | C8| C7| C6| C5| C4| C3| C2| C1| Base = 278/378/3BC Hex
* +---+---+---+---+---+---+---+---+ +---+
*/
#include<sys/io.h>
#include<unistd.h>
#include<stdlib.h>
#include<math.h> //for floor()
#include<iostream>
using namespace std;
#define BASEPORT 0x378 //SPP - Standard Parallel port base address
class stepper
{
private:
long delay; //delay betn each step
float pi; //constant
float acf, lcf; //angle and length correction factors in percentage
float r, c; // radius and circumerence of wheel
float ns;
int nfsc, nhs;
float residue;
// number of total steps, full step cycles and number of half steps
float step_rating; //number of steps per revolution
float speed; //speed of stepper in cm/sec
float l,w; //length and width of robocar
public:
stepper(float spd);
void specification();
void length2steps(float len, int& nfsc, int& nhs);//conversion
void angle2steps(float angle, int& nfsc, int& nhs);//conversion
void move(int nfsc, int nhs, int leftw, int rightw); //move
void fwd(float len); //length in cm
void bkwd(float len); //length in cm
void righturn(float degree, int degree_of_freedom); //number of degree turns
void lefturn(float degree, int degree_of_freedom); // -- do --
};
stepper:: stepper(float spd=7)
{
speed=spd;
l=18; //length of car
w=17-2; //width of car
acf=-2; //angle correction factor in percentage
lcf=-4; //angle correction factor in percentage
pi=3.14159; //costant
step_rating=200.5; //step rating
r=3.448; //radius of wheel in cm
c=2*pi*r; //circumference
residue=0;
//speed being in cm/s
delay=long(1/(step_rating/c*speed)*1000*1000); //in microsecond
}
void stepper::specification()
{
cout<<"\n\n\n\t\tF R O N T I E R\n";
cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
cout<<"\n\n\nDesigned by: Amit Kumar Karna";
cout<<"\n\n\nMission: Vitrubio, Technozion'06 @ NIT Warangal";
cout<<"\n\n\nROBOCAR specifications...";
cout<<"\nDimensions = "<<l<<"cm x"<<w<<"cm";
cout<<"\nWheel Dia = "<<2*r<<"cm";
cout<<"\nStepper motor: 12V-0.33A \t"<<step_rating<<" steps/revolution";
cout<<"\nLength n Angle correction factors: "<<lcf<<"% & "<<acf<<"% respectively";
cout<<"\nSpeed selected : "<<speed<<"cm/sec";
cout<<"\ndelay between each step = "<<delay/1000.0<<"ms";
cout<<endl<<endl<<endl;
}
void stepper::length2steps(float len, int& nfsc, int& nhs)//conversion
{
ns=step_rating/c*len+residue;
nfsc=int(ns/4);
nhs=int(floor((ns-nfsc*4)/0.5)); //rounding
if(nhs==8) //may result after rounding
nhs=7;
residue=ns-(nfsc*4+nhs*0.5);
}
void stepper::angle2steps(float angle, int& nfsc, int& nhs)//conversion
{
float arclen=(pi*w)/360.0*angle;
length2steps(arclen, nfsc, nhs);
}
void stepper::move(int nfsc, int nhs, int leftw, int rightw) //move
{
int i;
int cnt;
outb(0x00, BASEPORT);
if(leftw==1 && rightw==1)
{
for(i=0; i<nfsc; i++)
{
outb(0x59, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x95, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop to use break;
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==-1 && rightw==-1)
{
for(i=0; i<nfsc; i++)
{
outb(0x95, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0x59, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
}
}
else if(leftw==-1 && rightw==1) //left turn 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x99, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0x55, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==-1) //right turn with 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x55, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x99, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==0 && rightw==1) //left turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x09, BASEPORT);
usleep(delay);
outb(0x0A, BASEPORT);
usleep(delay);
outb(0x06, BASEPORT);
usleep(delay);
outb(0x05, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x01, BASEPORT);
if(++cnt==nhs)
break;
outb(0x09, BASEPORT);
if(++cnt==nhs)
break;
outb(0x08, BASEPORT);
if(++cnt==nhs)
break;
outb(0x0A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x02, BASEPORT);
if(++cnt==nhs)
break;
outb(0x06, BASEPORT);
if(++cnt==nhs)
break;
outb(0x04, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==0) //right turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x50, BASEPORT);
usleep(delay);
outb(0x60, BASEPORT);
usleep(delay);
outb(0xA0, BASEPORT);
usleep(delay);
outb(0x90, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x40, BASEPORT);
if(++cnt==nhs)
break;
outb(0x60, BASEPORT);
if(++cnt==nhs)
break;
outb(0x20, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA0, BASEPORT);
if(++cnt==nhs)
break;
outb(0x80, BASEPORT);
if(++cnt==nhs)
break;
outb(0x90, BASEPORT);
if(++cnt==nhs)
break;
outb(0x10, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
outb(0x00, BASEPORT);
}
void stepper::fwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving forward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, 1, 1);//leftw=1 & rightw=1
}
void stepper::bkwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving backward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, -1, -1);//leftw=-1 & rightw=-1
}
void stepper::lefturn(float angle, int dof=2) //degree of freedom
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking left turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 0, 1); //leftwheel=off, rightwheel=on
else
move(nfsc, nhs, -1, 1);
}
void stepper::righturn(float angle, int dof=2)
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking right turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 1, 0); //leftwheel=on, rightwheel=off
else
move(nfsc, nhs, 1, -1);
}
main()
{
system("clear");
if(ioperm(BASEPORT,3,1))
{
cout<<"\nThe parallel port accessing error!";
exit(1);
}
float speed; //in cm/s
float len, la, ra; //in cm
float angle;
long wait=10000;
//cout<<"\nEnter speed in cm/s (eg. 10cm/s) : ";
//cin>>speed;
speed=10;
stepper sm(speed);
sm.specification();
cout<<"\nScanning the problem...";usleep(wait);
cout<<"...";usleep(wait);cout<<"...";usleep(wait);cout<<"...";cout<<"Done!";
cout<<"\n\n\nStarting the voyage...\n\n\n";
float l1=20, l2=28.284;
float a1=45, a2=90, a3=135;
int i;
for(i=0; i<3; i++)
{
sm.fwd(l1);
usleep(wait);
sm.lefturn(a3);
usleep(wait);
sm.fwd(l2);
usleep(wait);
sm.righturn(a3);
}
}
base64 Encoding
#include <string.h>
#include <stdint.h>
//This is a helper function to convert a six-bit value to base64
char base64_encode_six(uint8_t six_bit_value){
uint8_t x;
char c;
x = six_bit_value & ~0xC0; //remove top two bits (should be zero anyway)
if( x < 26 ){
c = 'A' + x;
} else if ( x < 52 ){
c = 'a' + (x - 26);
} else if( x < 62 ){
c = '0' + (x - 52);
} else if( x == 62 ){
c = '+';
} else if (x == 63 ){
c = '/';
} else {
printf("ERROR IN BASE 64\n");
c = 'A';
}
return c;
}
//This is the function for encoding in base64
void base64_encode(char * dest, const char * src){
int bits;
int i;
int j;
int k;
int len;
uint8_t six_bits[4];
len = strlen(src);
k = 0;
//We need to encode three bytes at a time in to four encoded bytes
for(i=0; i < len; i+=3){
//First the thress bytes are broken down into six-bit sections
six_bits[0] = (src[i] >> 2) & 0x3F;
six_bits[1] = ((src[i] << 4) & 0x30) + ((src[i+1]>>4) & 0x0F);
six_bits[2] = ((src[i+1] << 2) & 0x3C) + ((src[i+2]>>6) & 0x03);
six_bits[3] = src[i+2] & 0x3F;
//now we use the helper function to convert from six-bits to base64
for(j=0; j < 4; j++){
dest[k+j] = base64_encode_six(six_bits[j]);
}
k+=4;
}
//at the end, we add = if the input is not divisible by 3
if( (len % 3) == 1 ){
//two equals at end
dest[k-2] = '=';
dest[k-1] = '=';
} else if ( (len %3 ) == 2 ){
dest[k-1] = '=';
}
//finally, zero terminate the output string
dest[k] = 0;
}
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__,________,________),
};
Binary numbers
// The following macros build values in binary. Nybbles are separated by
// commas for readability. If a non-binary digit is used, a compiler error
// will result. Here are some examples of the usage of the binary macros:
//
// B4 (0110) = 0x06
// B8 (0101,0101) = 0x55
// B16 (1010,1010, 0101,0101) = 0xAA55
// B32 (1000,0000, 1111,1111, 1010,1010, 0101,0101) = 0x80FFAA55
//
// For maximum readability, the bytes should be separated by spaces and there
// should be no spaces between nybbles, as shown above. Note that an enum
// isn't used because MISRA-C generates errors otherwise.
#define b0000 0u
#define b0001 1u
#define b0010 2u
#define b0011 3u
#define b0100 4u
#define b0101 5u
#define b0110 6u
#define b0111 7u
#define b1000 8u
#define b1001 9u
#define b1010 10u
#define b1011 11u
#define b1100 12u
#define b1101 13u
#define b1110 14u
#define b1111 15u
#pragma diag_suppress = Pm120
#define B4(n0) (b##n0) //!< Build a nybble in binary
#pragma diag_default = Pm120
#define B8(n1, n0) ((B4 (n1) << 4u) | B4 (n0))
//!< Build a byte in binary
#define B16(n3, n2, n1, n0) \
((B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a halfword in binary
#define B32(n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a word in binary
#define B64(nF, nE, nD, nC, nB, nA, n9, n8, n7, n6, n5, n4, n3, n2, n1, n0) \
((B4 (nF) << 60) | (B4 (nE) << 56) | (B4 (nD) << 52) | (B4 (nC) << 48) \
| (B4 (nB) << 44) | (B4 (nA) << 40) | (B4 (n9) << 36) | (B4 (n8) << 32) \
| (B4 (n7) << 28) | (B4 (n6) << 24) | (B4 (n5) << 20) | (B4 (n5) << 16) \
| (B4 (n3) << 12) | (B4 (n2) << 8) | (B4 (n1) << 4) | B4 (n0))
//!< Build a long in binary
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()
Exponential Moving Average
//This macros defines an alpha value between 0 and 1
#define DSP_EMA_I32_ALPHA(x) ( (uint16_t)(x * 65535) )
int32_t dsp_ema_i32(int32_t in, int32_t average, uint16_t alpha){
int64_t tmp0; //calcs must be done in 64-bit math to avoid overflow
tmp0 = (int64_t)in * (alpha) + (int64_t)average * (65536 - alpha);
return (int32_t)((tmp0 + 32768) / 65536); //scale back to 32-bit (with rounding)
}
//here is a function that uses the averaging code
int32_t my_avg_func(void){
static int32_t average = 0;
int32_t adc_value;
adc_value = read_the_adc_value();
average = dsp_ema_i32(adc_value, average, DSP_EMA_I32_ALPHA(0.1));
return average;
}
Binary Coded Decimal (BCD) - ASCII Converter
char bcdToAscii( unsigned char bcdNibble )
{
char result;
if( bcdNibble < 10 )
{// valid BCD input. ( [0,9] is the valid range for BCD input. )
result = (char)( bcdNibble + 48 ); // +48 is applicable to [0,9] input range.
}// end if
else
{// invalid input
result = '0';
}// end else
return( result );
}// end bcdToAscii()
unsigned char asciiToBcd( char asciiByte )
{/* Converts an input ASCII character (expected within the [ '0' - '9' ] range) into its BCD counterpart. */
unsigned char result;
if(
asciiByte >= '0'
&& asciiByte <= '9'
)
{// range check passed.
result = (unsigned char)(asciiByte - 48); // -48 offset gives the decimal value of the ASCII character.
}
else
{// range check failed.
result = 0;
}// end else
return( result );
}// end asciiToBcd()
Embedded Linux Frequency Meter
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/arch/gpio.h>
#include <asm/arch/dmtimer.h>
/*
The prescaler is enabled when TCLR bit 5 is set (PRE). The 2n division ratio value
(PTV) can be configured in the TCLR register.
Each internal interrupt source can be independently enabled/disabled in the interrupt
enable register TIER.
When the interrupt event has been issued, the associated interrupt status bit is set
in the timer status register (TISR). The pending interrupt event is reset when the
set status bit is overwritten by a 1.
The timer rate is defined by:
-Value of the prescaler fields (PRE and PTV of TCLR register)
-Value loaded into the timer load register (TLDR)
timer rate = (0xFFFF FFFF – TLDR + 1) x timer clock period x clock divider (PS)
PTV + 1)
PS = 2
*/
static unsigned long freq , ct, round;
extern struct omap_dm_timer * frequencimeter; // timer reserved to measure frequency
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg);
static int __init freqmeter_init(void)
{
int r;
round = 0; freq = 0 ; ct = 0;
printk(KERN_DEBUG "Init driver Freqmeter.\n");
/* request gpios*/
/* GPIO - P20_1610_GPIO4 */
if ( omap_request_gpio(4) < 0 ) printk(KERN_ERR "Error init GPIO4 (freqmeter).\n");
/* entrada */
omap_set_gpio_direction(4,1); /* in */
r = request_irq(OMAP_GPIO_IRQ(4), gpio4_freqmeter_irq_handler, IRQF_TRIGGER_RISING, "freqmeter", gpio4_freqmeter_irq_handler);
if ( r < 0 ) {
printk(KERN_ERR "freqmeter: request_irq() failed.\n");
return r;
}
printk(KERN_DEBUG "freqmeter initialized.\n");
return 0;
}
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg)
{
// dummy: no interrupt? freq = 0Hz
// only one int? freq = 0Hz
/** there is interference?: lread INT again
should be in same logic level */
if ( omap_get_gpio_datain(4) )
{
if(round > 0)
{
if(round == 50)
{
ct = omap_dm_timer_read_counter(frequencimeter);
omap_dm_timer_stop(frequencimeter);
ct /= 50;
freq = 1200000000/(ct +1);
printk("freq = %d\n",(freq/*-8*/));
round = 0xFFFFFFFF;
ct = 0;
freq = 0;
}
}
else // first read
{
freq = 0;
printk(KERN_DEBUG "Iniciou o freqmeter");
omap_dm_timer_write_counter(frequencimeter,0x0);
omap_dm_timer_start(frequencimeter);
}
round++;
}
return IRQ_HANDLED;
}
asmlinkage long sys_freq_read(void)
{
return freq;
}
static void __exit freqmeter_cleanup(void)
{
free_irq(OMAP_GPIO_IRQ(4), NULL);
omap_free_gpio(4);
}
module_init(freqmeter_init);
module_exit(freqmeter_cleanup);
MODULE_LICENSE("GPL");
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];
}