Starting out with embedded software
I frequently receive enquiries – generally emails – from engineers who are interested in getting into embedded software. They ask about what they should study, what programming languages are necessary etc. I would like to be helpful and commonly send a reply to these queries. However, I thought that it might be helpful to encapsulate a little guidance in a blog posting …
First off, I am not so sure that I am the right person with whom to discuss just starting out. For me, this experience is a long time ago, which I wrote about here. Having said, maybe I can still give some advice. In the end, like any technical job, getting a position in an embedded software development team is a question of having a suitable skill set and some experience.
The question of experience is a tough one. How can you have experience when you are looking for your first job? Some employers are enlightened enough to appreciate this problem and accept that a certain number of recruits will be “green”. The best ways to get some experience are to get an internship [i.e. work for no money] or work on personal projects and ensure that you have a good story to tell.
Defining the skill set is a little less vague, though specific things are more applicable to some industries than others. Also, an embedded software development team is not comprised of a bunch of engineers who all have the same set of skills and knowledge; some will, for example, have more hardware interface experience, whereas others might know about networking protocols or the application area of the device. It is very unlikely that anyone would have all the necessary prerequisites for every aspect of a development project.
So, here is my stab at some of the key matters to address:
- Learn C. It is the most common language used to develop embedded software and provides a reasonable basis for learning other languages.
- You might want to familiarize yourself with some of the standards that focus on using C safely – like MISRA C.
- Learn something about real-time operating systems – maybe Linux too.
- Learn some of the basics of electronics. You do not need to be able to design chips, but understanding, for example, why your software might see a 0 [not a 1] when a button is pressed might be useful.
- Learn some assembly language. Even if you really or never code it assembler, it is useful to be able to read it.
Jack Ganssle has some interesting views on this topic.
Although you can attend classes in embedded development – there are a number of excellent companies out there – there are plenty of other resources available. Books are a possibility. Although I lay claim to authoring the first book on embedded software [in 1986 – not totally relevant now] and plan another next year, there are lots to choose from. Of course, there are countless online resources. A good place to start is embedded.com where I write frequently, along with many knowledgeable authors.
A specific growth area in embedded software is automotive systems. For the most part, the skill set is unchanged, but some familiarity with AUTOSAR and OSEK/VDE may be useful.
If you have any learning suggestions or need advice on a specific resource, do leave a comment or get in touch by email or via social media.
Comments
Leave a Reply
You must be logged in to post a comment.
#include
#include
#include
#include
typedef float IOHWAB_FLOAT32;
char LV_Indicator_GPO = ‘R’, HV_Indicator_GPO = ‘Y’, HT_Indicator_GPO = ‘G’;
typedef struct
{
IOHWAB_FLOAT32 Battery_VoltageConverted;
IOHWAB_FLOAT32 TempSenseConverted;
} iohw_AdcDataConverted;
//Enumeration for various Vehicle state.
typedef enum Vehicle_Stat {
eLOCK_0 = 0,
eOFF_1 = 1,
eACC_2 = 2 ,
eON_4 = 4 ,
eSTART_5 = 5,
eSNA_7 = 7,
};
//Enumeration for threshold value of High, Low voltage and High Tempreature.
typedef enum Threshold_Value {
eTHRESHOLD_TEMPREATURE_HIGH_40 = 40,
eTHRESHOLD_VOLTAGE_HIGH_15 = 15,
eTHRESHOLD_VOLTAGE__LOW_9 = 9,
};
//Enumeration for writing on (HIGH) and off (LOW)to the signal.
enum eBoolean_State {
eHIGH = 1,
eLOW = 0,
};
void SWC_Rte_Write_High_Temperature_Indication(bool onoff);
void SWC_Rte_Write_Low_Volatge_Indication(bool onoff);
void SWC_Rte_Write_High_Volatge_Indication(bool onoff);
void SWC_Rte_Read_R_AdcDataConverted_AdcDataConverted(iohw_AdcDataConverted *datadata);
int SWC_Rte_Read_Ign_Stat();
void SWC_GPO_Selection();
int main(void)
{
system(“clear”);
printf(“\t\t\t*****************START OF THE APPLICATION*****************”);
SWC_GPO_Selection();
if((LV_Indicator_GPO == HV_Indicator_GPO) && (LV_Indicator_GPO == HT_Indicator_GPO))
{
printf(“%c GPO is set for all three Indicator.”,HT_Indicator_GPO);
}
else
{
printf(“\n%c : Low Voltage Indicator\n%c : High Voltage Indicator\n%c : High Tempreature Indicator”,LV_Indicator_GPO,HV_Indicator_GPO,HT_Indicator_GPO);
}
iohw_AdcDataConverted Input_Parameter_ADC;
int Vehicle_Ignition__Stat; // Vehicle Ignition state |e.g. LOCK = 0 , OFF = 1 , ACC = 2 , ON = 4 , START = 5, SNA = 7
Vehicle_Ignition__Stat = SWC_Rte_Read_Ign_Stat();
//Vehicle_Ignition__Stat = Rte_Read_Ign_Stat(c03_ISw_Stat ign_state);
//Do this while you get the correct Ignition state
if (Vehicle_Ignition__Stat == eLOCK_0 || Vehicle_Ignition__Stat == eOFF_1 || Vehicle_Ignition__Stat == eACC_2 || Vehicle_Ignition__Stat == eON_4 || Vehicle_Ignition__Stat == eSTART_5 || Vehicle_Ignition__Stat == eSNA_7)
{
if (Vehicle_Ignition__Stat == eON_4) // Vehicle is in ON state
{
//All GPO set to high.
printf(“Ignition mode on : Setting All GPO to High”);
SWC_Rte_Write_Low_Volatge_Indication(eHIGH);
SWC_Rte_Write_High_Volatge_Indication(eHIGH);
SWC_Rte_Write_High_Temperature_Indication(eHIGH);
}
else
{
SWC_Rte_Read_R_AdcDataConverted_AdcDataConverted(&Input_Parameter_ADC);
if(Input_Parameter_ADC.Battery_VoltageConvertedeTHRESHOLD_VOLTAGE_HIGH_15)
{
SWC_Rte_Write_High_Volatge_Indication(eHIGH); // High Voltage Indication
}
else
{
//GPO state is off because Voltage is in safe limits
SWC_Rte_Write_Low_Volatge_Indication(eLOW);
SWC_Rte_Write_High_Volatge_Indication(eLOW);
printf(“\n System Voltage is in Safe Limits.”);
}
if(Input_Parameter_ADC.TempSenseConverted>eTHRESHOLD_TEMPREATURE_HIGH_40)
{
SWC_Rte_Write_High_Temperature_Indication(eHIGH); // High Tempreature Indication
}
else
{
//GPO state is off because Tempreature is in safe limits
SWC_Rte_Write_High_Temperature_Indication(eLOW);
printf(“\n System Tempreature is in Safe Limits.”);
}
}
}
else
{
printf(“\nVehicle Ignition State you have Entred is Incorrect, Please select the correct Ignition state\n LOCK = 0 , OFF = 1 , ACC = 2 , ON = 4 , START = 5, SNA = 7\n “);
}
return 0;
}
void SWC_Rte_Write_High_Temperature_Indication(bool onoff)
{
if (onoff == 1)
{
if(HT_Indicator_GPO == ‘R’)
printf(“\n High Tempreature Observed : HT RED LED : ON”);
else if (HT_Indicator_GPO == ‘Y’)
printf(“\n High Tempreature Observed : HT YELLOW LED : ON”);
else if(HT_Indicator_GPO == ‘G’)
printf(“\n High Tempreature Observed : HT GREEN LED : ON”);
else
printf(“\n Invalid GPO selection.”);
}
else
printf(“\n High Tempreature not Observed”);
}
void SWC_Rte_Write_Low_Volatge_Indication(bool onoff)
{
if (onoff == 1)
{
if(LV_Indicator_GPO == ‘R’)
printf(“\n Low Voltage Observed : LV RED LED : ON”);
else if (LV_Indicator_GPO == ‘Y’)
printf(“\n Low Voltage Observed : LV YELLOW LED : ON”);
else if(LV_Indicator_GPO == ‘G’)
printf(“\n Low Voltage Observed : LV GREEN LED : ON”);
else
printf(“\n Invalid GPO selection.”);
}
else
printf(“\n Low Voltage not Observed.”);
}
void SWC_Rte_Write_High_Volatge_Indication(bool onoff)
{
if (onoff == 1)
{
if(HV_Indicator_GPO == ‘R’)
printf(“\n High Voltage Observed : HV RED LED : ON”);
else if (HV_Indicator_GPO == ‘Y’)
printf(“\n High Voltage Observed : HV YELLOW LED : ON”);
else if(HV_Indicator_GPO == ‘G’)
printf(“\n High Voltage Observed : HV GREEN LED : ON”);
else
printf(“\n Invalid GPO selection.”);
}
else
printf(“\n High Volatge not Observed “);
}
void SWC_Rte_Read_R_AdcDataConverted_AdcDataConverted(iohw_AdcDataConverted *data)
{
system(“clear”);
printf(“\nEnter Dummy Value of Voltage and Tempreature : “);
scanf(“%f %f”,&data->Battery_VoltageConverted,&data->TempSenseConverted);
}
int SWC_Rte_Read_Ign_Stat(int Ignition_State)
{
printf(“\n Please selecet the ignition Mode \n LOCK = 0 , OFF = 1 , ACC = 2 , ON = 4 , START = 5, SNA = 7\n”);
scanf(“%d”,&Ignition_State);
return Ignition_State;
}
void SWC_GPO_Selection()
{
system(“clear”);
uint8_t choice;
printf(“\nThere are 3 GPO i.e. RED , YELLOW , GREEN”);
printf(“\nYou can configure them with according to your choice : Any GPO can be configured as HV, LV, HT indicator.”);
printf(“\nPlease enter your GPO choice for Low Voltage Indicator\nPress 1 for RED GPO\nPress 2 for YELLOW GPO\nPress 3 for GREEN GPO\t”);
scanf(“%d”,&choice);
switch(choice)
{
case 1 :
{
LV_Indicator_GPO = ‘R’;
printf(“Please Select your GPO choice for High Voltage Indicator\nPress 1 for RED GPO\nPress 2 for YELLOW GPO\nPress 3 for GREEN GPO\t”);
scanf(“%d”,&choice);
switch(choice)
{
case 1 :
HV_Indicator_GPO = ‘R’;
HT_Indicator_GPO = ‘R’;
break;
case 2 :
HV_Indicator_GPO = ‘Y’;
HT_Indicator_GPO = ‘G’;
break;
case 3 :
HV_Indicator_GPO = ‘G’;
HT_Indicator_GPO = ‘Y’;
break;
default :
printf(“\nInvalid Choice : Please Reconfigure\n”);
SWC_GPO_Selection();
break;
}
}
break;
case 2 :
{
LV_Indicator_GPO = ‘Y’;
printf(“Please Select your GPO choice for High Voltage Indicator\nPress 1 for RED GPO\nPress 2 for YELLOW GPO\nPress 3 for GREEN GPO\t”);
scanf(“%d”,&choice);
switch(choice)
{
case 1 :
HV_Indicator_GPO = ‘R’;
HT_Indicator_GPO = ‘G’;
break;
case 2 :
HV_Indicator_GPO = ‘Y’;
HT_Indicator_GPO = ‘Y’;
break;
case 3 :
HV_Indicator_GPO = ‘G’;
HT_Indicator_GPO = ‘R’;
break;
default :
printf(“\nInvalid Choice : Please Reconfigure\n”);
SWC_GPO_Selection();
break;
}
}
break;
case 3 :
{
LV_Indicator_GPO = ‘G’;
printf(“Please Select GPO choice for High Voltage Indicator\nPress 1 for RED GPO\nPress 2 for YELLOW GPO\nPress 3 for GREEN GPO\t”);
scanf(“%d”,&choice);
switch(choice)
{
case 1 :
HV_Indicator_GPO = ‘R’;
HT_Indicator_GPO = ‘Y’;
break;
case 2 :
HV_Indicator_GPO = ‘Y’;
HT_Indicator_GPO = ‘R’;
break;
case 3 :
HV_Indicator_GPO = ‘G’;
HT_Indicator_GPO = ‘G’;
break;
default :
printf(“\nInvalid Choice : Please Reconfigure\n”);
SWC_GPO_Selection();
break;
}
}
break;
default :
printf(“Invalid Choice”);
SWC_GPO_Selection();
break;
}
}
#include
#include
#include
#include
#include
enum Vehicle_Stat {
NORMAL = 1,
CONFIGURATION = 2,
};
enum Boolean_State {
HIGH = 1,
LOW = 0,
};
void SWC_Rte_Write_Fault_Indication(bool onoff);
void SWC_Rte_Call_C_PwmDuty_PwmOperaion(uint8_t *Duty_cycle);
void SWC_Initialization(uint8_t Initialization_Time);
void SWC_Delay(float second);
void SWC_Warning_Lamp_Configuration();
int main(void)
{
system(“clear”);
printf(“\t\t\t******START OF THE APPLICATION***”);
uint8_t duty_cycle_temp;
uint8_t Initialization_time_temp;
printf(“\n Select the Mode of Vehicle.\t 1. NORMAL Mode. \t 2. CONFIGURATION Mode. “);
uint8_t Vehicle_Mode;
scanf(“%d”,&Vehicle_Mode);
if(Vehicle_Mode == NORMAL)
{
printf(“\n Vehicle is in NORMAL mode.”);
printf(“\n Default Case :”);
SWC_Rte_Write_Fault_Indication(LOW);
printf(“\n Enter the time for which GPIO would on and off after initialization (in second) : “);
scanf(“%d”,&Initialization_time_temp);
SWC_Initialization(Initialization_time_temp);
SWC_Warning_Lamp_Configuration();
}
else if(Vehicle_Mode == CONFIGURATION)
{
printf(“\n Vehicle is in CONFIGURATION mode.”);
SWC_Rte_Call_C_PwmDuty_PwmOperaion(&duty_cycle_temp);
}
else
{
printf(“\n Invalid choice.”);
}
return 0;
}
void SWC_Rte_Write_Fault_Indication(bool onoff)
{
system(“clear”);
if(onoff == LOW)
{
printf(” \n Warning Lamp Status : OFF”);
}
else
{
printf(“\n Warning Lamp Status : ON”);
}
}
void SWC_Delay(float second)
{
float mili_second = 1000000*(second);
clock_t start_time = clock();
while (clock() =0;i–)
{
system(“clear”);
SWC_Rte_Write_Fault_Indication(HIGH);
SWC_Delay(0.5);
SWC_Rte_Write_Fault_Indication(LOW);
SWC_Delay(0.5);
//printf(“\n Time Remaining : %d”,i);
//printf(“\n Initialization Start : %d second Remaining.”, i);
//delay(Initialization_Time);
}
printf(“\n Initialization Time Over.”);
}
void SWC_Rte_Call_C_PwmDuty_PwmOperaion(uint8_t *Duty_cycle)
{
uint8_t Periodicity;
printf(“\n Enter the duty cycle in percent(from 0 to 100) : “);
scanf(“%d”,Duty_cycle);
if((*Duty_cycle) >= 0 && (*Duty_cycle) <= 100)
{
printf(" Enter Periodicity : ");
scanf("%d",&Periodicity);
printf("\n Duty Cycle is %d percent.",*Duty_cycle);
printf("\n Periodicity is %d HZ.",Periodicity);
float On_Time,Off_Time;
On_Time = (float)(*Duty_cycle)/(100*Periodicity);
Off_Time = (float)(100-(*Duty_cycle))/(100*Periodicity);
// On_Time + Off_Time = 1 (for 1 HZ frequency)
printf("\nOn time is %f and off time is %f", On_Time,Off_Time);
while(1)
{
system("clear");
SWC_Rte_Write_Fault_Indication(HIGH);
SWC_Delay(Off_Time);
SWC_Rte_Write_Fault_Indication(LOW);
SWC_Delay(On_Time);
}
}
else
{
printf("\n Invalid Duty Cycle. (NOTE : Duty Cycle must be between 0-100. ) ");
}
}
void SWC_Warning_Lamp_Configuration()
{
uint8_t choice;
printf("\n Please Configure the GPIO through which fault would be detected.\n 1.via Hardware\t \t2.via CAN\t3.via both\t");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
printf("\n Warning Lamp is Configure to Detect fault via Hardware.");
printf("\n You can Enable or Disable the Warning Lamp via Hardware.\n Please Select an option. 1. Enable WL \t 2. Disable WL \t 3. Not Intrested ");
scanf("%d",&choice);
switch(choice)
{
case 1:
SWC_Rte_Write_Fault_Indication(HIGH);
break;
case 2:
SWC_Rte_Write_Fault_Indication(LOW);
break;
case 3:
break;
default:
printf("\n Invalid Choice.");
break;
}
}
break;
case 2:
printf("\n Warning Lamp is Configure to Detect fault via CAN.");
break;
case 3:
printf("\n Warning Lamp is Configure to Detect fault via Hardware and CAN.");
break;
default:
printf("\n Invalid Choice.");
SWC_Warning_Lamp_Configuration();
break;
}
}