Smart Car Race Layered architecture The ability to provide a design of different levels of abstraction can Simplify the design considerably Enable different role players to effectively Work at various levels of abstraction Systems design and business process design can both use this. Some design processes specifically generate designs that contain various levels of abstraction. Layered architecture partitions the concerns of the application into stacked groups (layers). it is a technique used in designing computer software, hardware, and communications in which system or network components are isolated in layers so that changes can be made in one layer without affecting the others. Layers used in the Smart Car Race Project APP PID Position HAL Servo Motor Sensors LCD/Buttons PI Motors MAL ADC eMIOS GPIO Motores MAL (Microcontroller Abstraction Layer) ADC The analog-to-digital converter (ADC) block provides accurate and fast conversions for a wide range of applications. An ADC module has a corresponding digital interface. The ADC digital interface contains advanced features for normal or injected conversion. A conversion can be triggered by software or hardware (Cross Triggering Unit or PIT). There are three types of input channels: • Internal precision, ADC0_P[n] (internally multiplexed precision channels) • Internal standard, ADC0_S[n] (internally multiplexed standard channels) • External ADC0_X[n] (externally multiplexed standard channels) The mask registers present within the ADCDig can be programmed to configure which channel has to be converted. Three external decode signals MA[2:0] (multiplexer address) are provided for external channel selection and are available as alternate functions on GPIO. The MA[0:2] are controlled by the ADC itself and are set automatically by the hardware. A conversion timing register for configuring different sampling and conversion times is associated to each channel type. Normal conversion This is the normal conversion that the user programs by configuring the normal conversion mask register (NCMR). Each channel can be individually enabled by setting ‘1’ in the corresponding field of NCMR registers. Mask registers must be programmed before starting the conversion and cannot be changed until the conversion of all the selected channels ends (NSTART bit in the Main Status Register (MSR) is reset). Normal Conversion Operating Modes Two operating modes are available for the normal conversion: • One Shot • Scan To enter one of these modes, it is necessary to program the MCR[MODE] bit. The first phase of the conversion process involves sampling the analog channel and the next phase involves the conversion phase when the sampled analog value is converted to digital. In Scan Mode (MODE = 1), a sequential conversion of N channels specified in the NCMR registers is continuously performed. As in the previous case, at the end of each conversion the digital result of the conversion is stored into the corresponding data register. The MSR[NSTART] status bit is automatically set when the Normal conversion starts. Unlike One Shot Mode, the MCR[NSTART] bit is not reset. It can be reset by software when the user needs to stop scan mode. In that case, the ADC completes the current scan conversion and, after the last conversion, also resets the MSR[NSTART] bit. ADC used in the Smart Car Race Project Functions For the Smart Car Race, we use 11 ADC channels in Scan Mode, each one for every phototransistor of the sensor board. The idea is to multiplexing each sensor to obtain the analog value to know which color is sensing the phototransistor. In the code we used 3 functions to manipulate this Layer. The next Table 1.1 shows how the functions work. Function How it works void ADC_init(void); In this function, the ADC is configurated to works in Scan Mode, setting the bit 2 of the MCR (Main Configuration Register) void ADC_paths(void); Configuration of the paths in ADC mode unsigned long ADC_shot(int lub_channel) This function returns an unsigned long value which is the ADC Conversion. In the argument, the channel is declared by the user. This function works very easy and it can be really useful and powerful to work with. Table 1.1- Functions and how they work. Variables and #Defines In the ADCHeader, we declared the variables used in this layer. The principal function of the variables and defines is to have the possibility to make changes without change large lines of code, it makes possible the portability. We know that we don’t need to make the code portable, but we decide this just to show the rules and recommendations that were taught in the courses. Macros and Variables Name Register or Constant 1. ADC_channel Macro used to configure the Normal Conversion Mask Register 0 (NCMR0). Sets the channel used for conversion. 2. ADC_start Macro used to configure the Normal Convertion. Setting this bit starts the chain or scan conversion. 3. ADCconfiguration Macro used to configure the Main Configuration Register (MCR). Sets the Mode of operation. 4. ADCtimeConvertion Macro used to configure the Conversion timing registers. Sets the conversion time. 5. ADC_pad[1:11] Macro used to configure the pads as ADC function. 6. luw_channel Stores the number of the channel that we want to get the analog Value. 7. luw_potencia Using an algorithm, this variable gets the number of the channel, then we have to shift the lub_potencia variable because our ADC channel starts in the number 4 (ANP4). 8. lul_resultado Stores the value of the ADC convertion. eMIOS The eMIOS provides functionality to generate or measure time events. The eMIOS uses timer channels that are reduced versions of the unified channel (UC) module used on MPC555x devices. Each channel provides a subset of the functionality available in the unified channel, at a resolution of 16 bits, and provides a user interface that is consistent with previous eMIOS implementations. Modulus Counter (MC) mode The MC mode can be used to provide a time base for a counter bus or as a general purpose timer. Bit MODE[6] selects internal or external clock source when cleared or set, respectively. When external clock is selected, the input signal pin is used as the source and the triggering polarity edge is selected by the EDPOL and EDSEL in the EMIOSC[n] register. The internal counter counts up from the current value until it matches the value in register A1. Register B1 is cleared and is not accessible to the MCU. Bit MODE[4] selects up mode or up/down mode, when cleared or set, respectively. When in up count mode, a match between the internal counter and register A1 sets the FLAG and clears the internal counter. The timing of those events varies according to the MC mode setup as follows: • Internal counter clearing on match start (MODE[0:6] = 001000b) o External clock is selected if MODE[6] is set. In this case the internal counter clears as soon as the match signal occurs. The channel FLAG is set at the same time the match occurs. Note that by having the internal counter cleared as soon as the match occurs and incremented at the next input event a shorter zero count is generated. o Internal clock source is selected if MODE[6] is cleared. In this case the counter clears as soon as the match signal occurs. The channel FLAG is set at the same time the match occurs. At the next prescaler tick after the match the internal counter remains at zero and only resumes counting on the following tick. • Internal counter clearing on match end (MODE[0:6] = 001001b) o External clock is selected if MODE[6] is set. In this case the internal counter clears when the match signal is asserted and the input event occurs. The channel FLAG is set at the same time the counter is cleared. o Internal clock source is selected if MODE[6] is cleared. In this case the internal counter clears when the match signal is asserted and the prescaler tick occurs. The channel FLAG is set at the same time the counter is cleared. When in up/down count mode (MODE[0:6] = 00101bb), a match between the internal counter and register A1 sets the FLAG and changes the counter direction from increment to decrement. A match between register B1 and the internal counter changes the counter direction from decrement to increment and sets the FLAG only if MODE[5] bit is set. Only values different than 0x0 must be written at A register. Loading 0x0 leads to unpredictable results. Updates on A register or counter in MC mode may cause loss of match in the current cycle if the transfer occurs near the match. In this case, the counter may rollover and resume operation in the next cycle. Register B2 has no effect in MC mode. Nevertheless, register B2 can be accessed for reads and writes by addressing EMIOSB. Output Pulse Width Modulation Buffered (OPWMB) Mode OPWMB mode (MODE[0:6] = 11000b0) is used to generate pulses with programmable leading and trailing edge placement. An external counter driven in MCB Up mode must be selected from one of the counter buses. A1 register value defines the first edge and B1 the second edge. The output signal polarity is defined by the EDPOL bit. If EDPOL is zero, a negative edge occurs when A1 matches the selected counter bus and a positive edge occurs when B1 matches the selected counter bus. The A1 and B1 registers are double buffered and updated from A2 and B2, respectively, at the cycle boundary. The load operation is similar to the OPWFMB mode. FLAG can be generated at B1 matches, when MODE[5] is cleared, or in both A1 and B1 matches, when MODE[5] is set. If subsequent matches occur on comparators A and B, the PWM pulses continue to be generated, regardless of the state of the FLAG bit. FORCMA and FORCMB bits allow the software to force the output flip-flop to the level corresponding to a match on A1 or B1 respectively. FLAG bit is not set by the FORCMA and FORCMB operations. At OPWMB mode entry the output flip-flop is set to the value of the EDPOL bit in the EMIOSC[n] register. Some rules applicable to the OPWMB mode are: • B1 matches have precedence over A1 matches if they occur at the same time within the same counter cycle. • A1 = 0 match from cycle n has precedence over B1 match from cycle n-1. • A1 matches are masked out if they occur after B1 match within the same cycle. • Any value written to A2 or B2 on cycle n is loaded to A1 and B1 registers at the following cycle boundary (assuming OU[n] bit of EMIOSOUDIS register is not asserted). Thus the new values will be used for A1 and B1 matches in cycle n+1. eMIOS used in the Smart Car Race Project For the Smart Car Race, we used the eMIOS with three different modes. Modulus Counter, Output Pulse Width Modulation Buffered and Input Width Modulation Buffered. Basically, the eMIOS is used to control three drivers of the car, the motors, the servomotor and the camera. The “Table 2.1” shows how the eMIOS work in each driver: Motor ServoMotor • Using the OPWM we control the power consumed by the motors. • With a OPWM signal with a small duty cycle, we can control the position of the servomotor. Functions of the EMIOS_Driver To have a good idea of what’s happening in the driver, we just initialize and configure the channels and the respective registers to generate each signal. The Table 2.2 shows how each function works. Function How it works 1. vfn_initEMIOS_1(void); Handling the MCR register to initialize the EMIOS Modulus. Writes “15” in the bits of GPRE to divide the clock by 16 (15+1) what led us a clock of 4 MHz because we are using the clock as 64MHz. In the same way, we enable the eMIOS clock, the global time base and the stopping channels when is in debug mode. 2. vfn_initEMIOS_chOPWM(T_UBYTE lub_EMIOS_ch,T_UWORD luw_busA, T_UWORD luw_busB, T_UBYTE lub_counterBus); The EMIOS channel is initialized writing in the Control Register the mode as OPWM, the counterBus and the polarity-leading edge. In the argument of the function we enable the EMIOS channel we want to initialize, the value of the Register A and B and the counter bus we want to use. 3. vfn_initEMIOS_modCnt(T_UBYTE lub_cntCh, T_UWORD luw_period, T_UBYTE lub_prescaler); The clock base is generated in this function. To generate it, we have to configure the counter modulus and indicate the period of the clock. The arguments of the function are the counter channel and the period of the clock. 4. vfn_initEMIOS_pad(T_UBYTE lub_pad); Initialize the pad in the EMIOS function in the PCR register of the System Integration Unit Lite (SIU). Variables and constants in the Driver Function Properties Function: vfn_initEMIOS_chOPWM 1. lub_EMIOS_ch Stores: The number of the EMIOS channel we want to initialize and modify as a PWM. Function: vfn_initEMIOS_chOPWM 2. luw_busA Stores: The value of the register we want to change to modify the duty Cycle of the signal PWM. Function: vfn_initEMIOS_chOPWM 3. luw_busB Stores: The value of the register B. In the mode PWM it’s usually initialized with the same value of the period. Function: vfn_initEMIOS_chOPWM 4. lub_counterBus Stores: The value of the counter bus where the Modulus Counter will place the signal generated. Bus A (0x0), bus B,C,D,F (0x1) and internal bus (0x3). Function: vfn_initEMIOS_modCnt 5. lub_cntCh Stores: The value of the EMIOS channel used as a Modulus Counter. Function: vfn_initEMIOS_modCnt 6. luw_period Stores: The period of the signal that we want to generate with the modulus counter. Ex: If we store (999 + 1) and we have a signal of 1MHz, the Modulus Counter will generate a signal of 1KHz. 7. lub_prescaler Function: vfn_initEMIOS_modCnt Stores: The prescaler of the general clock. If the EMIOS clock is 4MHz and if our prescaler variable is (3 + 1), at the end our signal will be 1MHz. Function: vfn_initEMIOS_pad 8. lub_pad Stores: The number of the pad we want initialize with the EMIOS function. Sistem Integration Unit Lite (SIUL) The System Integration Unit Lite (SIUL) controls the MCU pad configuration, ports, generalpurpose input and output (GPIO) signals and external interrupts with trigger event configuration. The module provides the capability to configure, read, and write to the device’s general-purpose I/O pads that can be configured as either inputs or outputs. When a pad is configured as an input, the state of the pad (logic high or low) is obtained by reading an associated data input register. When a pad is configured as an output, the value driven onto the pad is determined by writing to an associated data output register. Enabling the input buffers when a pad is configured as an output allows the actual state of the pad to be read. To enable monitoring of an output pad value, the pad can be configured as both output and input so the actual pad value can be read back and compared with the expected value. Pad Configuration Registers (PCR0–PCR122) The Pad Configuration Registers allow configuration of the static electrical and functional characteristics associated with I/O pads. Each PCR controls the characteristics of a single pad. Please note that input and output peripheral muxing are separate. • For output pads: — Select the appropriate alternate function in Pad Config Register (PCR) — OBE is not required for functions other than GPIO • For INPUT pads: — Select the feature location from PSMI register — Set the IBE bit in the appropriate PCR • For normal GPIO (not alternate function): — Configure PCR — Read from GPDI or write to GPDO Table 1.1- PCR description Analog Pad Control (APC) This bit enables the usage of the pad as analog input. — 0: Analog input path from the pad is gated and cannot be used — 1: Analog input path switch can be enabled by the ADC Pad Output Assignment (PA [1:0]) This field is used to select the function that is allowed to drive the output of a multiplexed pad. — — — — 00: Alternative Mode 0 — GPIO 01: Alternative Mode 1 — See the signal description chapter 10: Alternative Mode 2 — See the signal description chapter 11: Alternative Mode 3 — See the signal description chapter Output Buffer Enable (OBE) This bit enables the output buffer of the pad in case the pad is in GPIO mode. — 0: Output buffer of the pad is disabled when PA[1:0] = 00 — 1: Output buffer of the pad is enabled when PA[1:0] = 00 Input Buffer Enable (IBE) This bit enables the input buffer of the pad. — 0: Input buffer of the pad is disabled — 1: Input buffer of the pad is enabled GPIO Pad Data Output Registers These registers are used to set or clear GPIO pads. Each pad data out bit can be controlled separately with a byte access. Pad Data Out This bit stores the data to be driven out on the external GPIO pad controlled by this register. — 0: Logic low value is driven on the corresponding GPIO pad when the pad is configured as an output. — 1: Logic high value is driven on the corresponding GPIO pad when the pad is configured as an output. GPIO Pad Data Input Registers These registers are used to read the GPIO pad data with a byte access. Pad Data In This bit stores the value of the external GPIO pad associated with this register. — 0: Value of the data in signal for the corresponding GPIO pad is logic low — 1: Value of the data in signal for the corresponding GPIO pad is logic high SIUL in the Smart Car Race The System Integrate Unite Lite is used to configure pads with different functions, ADC, EMIOS and GPDIO. In order to have organization in our code, each function is assigned in each driver, depending the functionality of the pad is the driver that configures it. Functions of the GPDIO_Driver Function How it works 1. vfn_initGPDIOout(T_UWORD lub_gChannel); Initialize the PCR of the channel “lub_gChannel” as Output. 2. vfn_initGPDIOin(T_UBYTE lub_gChannel); Initialize the PCR of the channel “lub_gChannel” as Input. 3. vfn_setGPDO(T_UWORD lub_gChannel, T_UBYTE lub_gValue); Sets the “lub_gValue” to the channel “lub_gChannel”. The variable “lub_gValue” can be just ‘0’ or ‘1’ because GPDO is just for one bit. Macros and Variables Name Register or Constant 1. luw_gChannel Stores the number of the PCR register. 2. lub_gValue Stores the value that is assigned to a pad. HAL (Hardware Abstraction Layer) Motors One of the main parts of the system is the Motors. If we have a simple and easy way to control the motors we will be able to introduce other complex controllers to the system. Our idea is to convert the percentage of power consumption we want into the duty cycle of the PWM signal that we are going to generate. Power Consumption Duty Cycle of the PWM signal To generate the entire driver, we have to use the EMIOS driver to initialize the channels and the pads that we are going to use with this functionality. First we initialize the eMIOS, the counter modulus and the pad of the motors. This is just one function. Then, we have another function to convert a value in the range of 0 and 100, which is the power consumption, into the period we need to generate a signal with those characteristics. Functions of the Motor Driver Function How it works 1. vfn_initMotors(void); Initialize the eMIOS, the counter modulus with a frecuency of 1000Hz and the pad used to control the motors. 2. vfn_setDuty(T_UBYTE lub_dutyCycle); Sets the duty Cycle of the PWM signal just multiplying the variable “lub_dutyCycle” for 10 to get a value between 0 and 1000 which is the value used as period in the bus A. Macros and Variables Name Value or Register 1. cub_MotorEMIOSch EMIOS channel used for the Motors. Value = 6 2. cub_MotorPad Number of the PCR of the emios channel 6. Value = 116 3. cub_MotorCntCh EMIOS channel used as a Modulus Counter. Value = 23 4. cuw_MotorPeriod Period wanted for the PWM 1ms - 1KHz. Value = (999 + 1) 5. cuw_MotorBbus Constant of the Bus B. Value = (999 + 1) 6. cub_MotorCntBus Define the Bus A as default. Value = 0 7. cub_MotorPrescaler In order to have a signal of 1MHz we have to divide the max frequency by (3+1) = 4 8. lub_dutyCycle Variable written in the argument of the function to set the motor at “lub_dutyCycle” power consumption. 9. luw_MotorAbus Variable used to Convert dutyCycle to Period. Sensors Driver Functions Functions How it works 1. vfn_initSensors(void); Initialize the ADC timing conversion, the pads used as ADC channels and the mode of operation of the ADC. It also initialize the pads as general purpose (GPDO), used to multiplex each sensor and avoid interference noise. 2. vfn_getSensors_Value(void); Gets the Value of each sensor and puts the value in an array, each sensor is multiplexed to get one value at a time so we can save energy and avoid noise. Macros and Variables Name 1. cub_FirstSensorPad Value or Register First pad of the multiplexer port. Used like a base to know the first pad we are going to multiplex. Servomotor Driver Functions Function How it works 1. vfn_initServo(void); Initialize the eMIOS driver to generate the signal of the Servo. The signal has a frequency of 62.5Hz with a period of 0.016 seconds. 2. vfn_setServoPos(T_UBYTE lub_ServoGrados); With this function, we just have to assign the degrees and the servo will spin in that position. Macros and Variables Name Value or Register 1. cub_Servo_pad Pad used for the Servo PH3. Value = 115 2. cub_Servo_emiosCh EMIIOS channel used for the Servo. Value = 5 3. cub_Servo_Cntch Number of the Modulus counter used for the Servo. Value = 0 4. cuw_Servo_Period Period of the Servo Signal. Value = (15999 + 1) = 16000 (16ms) -> (62.5Hz) 5. cub_Servo_prescaler Prescaler used to get a signal of 1MHz in the Modulus Counter. Value = 3 6. cub_Servo_counterbus Constant that assign the bus B to the PWM Value = 0x1 7. cub_Servo_calibration Calibration to have a straightforward direction with 90° degrees. Value = 4 8. lub_ServoGrados Stores the value of the degrees that we want to set the servo. 9. lf_Servo_Aperiodo Stores the value of the equation used to get the period. 10. luw_SerPeriod Stores the Period in an integer value. APP (Application Layer) PID Driver Implementation To know the position of the Line in the entire line of sensors we decide to weight each sensor. In order to get two data in just one variable, we decide to weight the values of the sensors. The magnitude of this weight values decides how much we have to spin the servomotor and the sign of this variable decides the side of the spin. N° of the Sensor Weight Value 1 2 3 4 5 6 7 8 9 10 11 | (-5) | (-4) | (-3) | (-2) | (-1) | (0) | (1) | (2) | (3) | (4) | (5) ADC Value Voltage Value Weight Value Final Error Process of the data in the PID Implementation of the PID One of the critical steps in the Control of the Car was how to get the error. The weight values answered this question. The weight values give us the opportunity to know, with just one variable, the position of the car in relation of the line. For example, let’s say that the car is a little bit moved right of the line. If we know the answer of the black color, which is in the range of (2.3 3.5) and the answer of the white color, between (0.2 – 1.2), we can get the value of each side and then add both parts. The left part will be weight with negative values and the right part of the board with positives. So, in the example, the voltage of the sensor would be: #Sensor 1 Value 0.2 2 0.2 3 0.2 4 0.2 5 0.2 6 0.2 7 2.3 8 2.3 9 0.2 10 0.2 11 0.2 10 0.2 (4) 0.8 11 0.2 (5) 1 The next step would be multiply the Values of the voltages and the weight values: #Sensor Value Weight V. Final 1 0.2 (-5) -1 2 0.2 (-4) -0.8 3 0.2 (-3) -0.6 4 0.2 (-2) -0.4 5 0.2 (-1) -0.2 6 0.2 (0) 0 7 2.3 (1) 2.3 8 2.3 (2) 4.6 9 0.2 (3) 0.6 Then, we create a variable of each side: Variable_Left_Side = (-1) + (-0.8) + (-0.6) + (-0.4) + (-0.2) = -3 Variable_Right_Side = (2.3) + (4.6) + (0.6) + (0.8) + (1) = 9.3 Error = Variable_Left_Side + Variable_Right_Side = (-3) + (9.3) = 6.3 As we can see, if the black line is shifted more in the right side, the error will be higher. It’s the same if the line is in the left part but the error will be negative. Then, the Integral and Derivative value are compute. Integral_Value = Integral_Value + Error Derivative_Value = Error – Last_Error Once we have the three parts of the PID controller we have to eliminate the error spinning the Servo and changing the velocity of the motors. After that, we are able to compute again the error. This process is showed in the next flowchart. Starts PID Obtain the value of the sensors The conversion is converted into voltage Each voltage of the sensors is weighted to get a better error of the system Computes the error Computes the integral and derivative values If the error > MaxTurn Yes Assign the maximum shift to the servo. Sets the ServoMotor and the Motors depending of the error PID flowchart No Compute the shift in base of the error Functions Function How it works 1. vfn_initPID(void) This function Initialize the driver of the Motors, the Sensors and the Servomotor 2. vfn_setPIDposition(void) First, the function compute the value of the error. Macros and Variables Name Value or Register 1. Kp Constant of proportionality 2. Ki Constant of integral 3. Kd Constant of derivative 4. Km Constant of proportionality of the motor 5. MaxVoltage Maxim Voltage used to compute the real Voltage value 6. Resolution Resolution of the ADC (10 bits) 7. rsf_PIDerror Probably, this variable is one of the most important variables of the system because it tells us how far or how much we have to spin the servo to stabilize the car and be in the middle of the line. 8. rsf_PIDneg We add the left part of the sensors (the negative one) to have a reference of the left part of the sensors board. 9. rsf_PIDpos We add the right part of the sensors (the positive one) to have a reference of the right part of the sensors board. 10. casw_PIDweightValues Stores the constants of the weighted values used to help the process to manage the data. This array gives a specific weight to each sensor, giving us more information about where is the line. 11. raf_PIDvoltageweight Stores the value of the voltage weighted. Once we have the real value of the voltage, we multiply each position of the weight values to each position of the voltage values. The result is saved here. 12. raf_PIDvoltage Stores the value of the real Voltage measured by the ADC 13. ruw_PIDTurn Stores the conversion Error -> Turn to put it in the Servo 14. rsf_PIDderivative Stores the value of the derivative part of the PID 15. rsf_PIDintegral Stores the value of the integral part of the PID 16. rsf_PIDLastError Store the memory of the last error used by the derivative part Scheduler Configuration of the Scheduler To be able to have a real Time response, we define only 2 tasks in the Scheduler. The propose to have only 2 task is to divide the tasks in two groups. In the First group, we have two features, this features get the feedback of our system. This feedback is obtained by the sensors and then computed them by the PID feature. Scheduler Table Our other group is the response of our motors to stabilize the system. The first feature is the servomotor, this feature reacts depending of the error signal, as higher is the error as higher is the spin of the servo. In the same way, the Motors accelerate when the error is low and the integral value is low. This ensures the stability of the car even if the sensors board is out of the line. Procedure of the Control Group Procedures of the Response Group Why we use the Scheduler? According to our delay times in the Tasks, we assign 2 ms for the Control group and 4 ms for the Response group. This means that the Control Group will be execute 2 times for each time the Response Group is executed. But the question is why? The answer is the integral and derivative values. If we execute the PID control a lot of times, our system will respond more precisely. It is true that the Servo and the motors just see the proportional value of the same process, but it is also true that they will see the integral and derivative values of both processes. This is really helpfully because we will have a record of those values that need to be observed at any time. The next Table shows how the Tasks are executed. Tasks