EmbeddedRelated.com

Primitive exception processing using macros

Ricky Bennett March 22, 2013 Coded in C
#define Try \
      jmp_buf ExceptionBuffer; \
      int ExceptionStatus = setjmp (ExceptionBuffer); \
      if (ExceptionStatus == 0)

#define Catch(Value)    else if (ExceptionStatus == (int) (Value))

#define Finally         else

#define Throw(Value) \
      { \
         int Result = (int) (Value); \
         if (Result != 0) { \
            longjmp (ExceptionBuffer, Result); \
         } \
      }

An example using a function to read the OCR register on an SD card:

uint32_t SDCard_OCR (void) {
   SDCard_ConfigSSP ( );
   Try {

      // The card is asked to send its OCR.  The OCR is
      // placed in module variable mOCRValue by the
      // function.
      Throw (SDCard_SendCommand (CMD58_READ_OCR));
   }

   // Error processing.
   Catch (SD_TIMEOUT) {
      GUI_SendMessage (SDCARD_TIMEOUT);
   }
   Catch (SD_NO_CARD) {
      GUI_SendMessage (SDCARD_NOT_FOUND);
   }
   Finally {   // Unknown SD card error
      Throw (SD_NO_CARD);   // Rethrow the exception
   }

   // Executed even if an exception thrown:
   SDCard_DeconfigSSP ( );
   return mOCRValue;   // 0xFFFFFFFF if error
}

Simple Bit Manipulation Macros

Stephen Friederichs March 12, 20134 comments Coded in C
/* 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))

Delay for MSP430

March 12, 20132 comments Coded in C for the TI MSP430
void configureClocks();
void delay_ms(unsigned int ms);
void delay_us(unsigned int us);

void configureClocks()
{
     WDTCTL = WDTPW + WDTHOLD;          // Stop WDT
     BCSCTL1 = CALBC1_1MHZ;
     DCOCTL = CALDCO_1MHZ;

 }

void delay_us(unsigned int us)
{
	while (us)
	{
		__delay_cycles(1); // 1 for 1 Mhz set 16 for 16 MHz
		us--;
	}
}

void delay_ms(unsigned int ms)
{
	while (ms)
	{
		__delay_cycles(1000); 1000 for 1MHz and 16000 for 16MHz
		ms--;
	}
}

PID (Floating Point)

March 5, 2013 Coded in C
/*! \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;
}

Additive White Gaussian Noise Generator

Dr Cagri Tanriover March 3, 20131 comment Coded in C
#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()

base64 Encoding

March 1, 20132 comments Coded in C
#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

Ricky Bennett February 28, 20132 comments Coded in C
// 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

Ricky Bennett February 28, 2013 Coded in C
// 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

Dr Cagri Tanriover February 18, 20131 comment Coded in C
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

February 13, 20133 comments Coded in C
//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;
}