Configuring Kinetis Software Development Kit (SDK) to measure distance with infrared (IR) sensor

Document created by Abigail Inzunza Lopez Employee on Jan 9, 2015Last modified by Diana Torres on Feb 28, 2017
Version 6Show Document
  • View in full screen mode

For this demo, Kinetis SDK was configured to implement a distance meter using a FRDM-K64F and the GP2D12 IR Sensor. The operating principle of this sensor consists in sending IR pulses and according to the existing distance between it and the reflective object, it generates different output voltages. Its analog output varies from 0.4 to 2.6 V approximately; the higher output voltage values are reached when the reflective object is closer to the sensor and the lower ones when it’s farther. The range of distance measured goes from 15 to 100 cm, if the distance from the sensor to the reflective object isn’t between this range, the demo’s results will not be reliable.

The following figure depicts the application’s block diagram

figure 1.jpg

Figure 1. Block Diagram

The signal received from the sensor goes through the Channel_1 at the instance 0 of the ADC module (ADC0_CH1), which is periodically triggered by the low power timer (every 125 µs). After getting every ADC’s sample an average is calculated from a total of 32 samples in order to make the ADC’s value reliable before using it to calculate the current distance.

The application’s schematic diagram is shown in the following figure

figure 2.jpg

Figure 2. Schematic Diagram

The required electrical connections to implement the application are explained below

Table 1.PNG.png

Table 1. Electrical connections

  The following figure shows the application’s flow diagram

figure 3.jpg

   Figure 3. Flow Diagram


The required configuration for the ADC initialization in the application is shown on the following code snippet

static int32_t init_adc(uint32_t uiInstance) {     /*      * Initialization ADC for      * 10bit resolution, interrrupt mode, hw trigger enabled.      * normal convert speed, VREFH/L as reference,      * disable continuous convert mode.      */     ADC16_DRV_StructInitUserConfigDefault(&adcUserConfig);     adcUserConfig.intEnable = true;     adcUserConfig.resolutionMode = kAdcResolutionBitOf10or11;     adcUserConfig.hwTriggerEnable = true;     adcUserConfig.continuousConvEnable = false;     adcUserConfig.clkSrcMode = kAdcClkSrcOfAsynClk;     ADC16_DRV_Init(uiInstance, &adcUserConfig);      /* Install Callback function into ISR. */     ADC_TEST_InstallCallback(uiInstance, CHANNEL_0, MyADCIRQHandler);      adcChnConfig.chnNum = IR_SENSOR_ADC_CHANNEL;     adcChnConfig.diffEnable = false;     adcChnConfig.intEnable = true;     adcChnConfig.chnMux = kAdcChnMuxOfA;     /* Configure channel0. */     ADC16_DRV_ConfigConvChn(uiInstance, CHANNEL_0, &adcChnConfig);      return 0; }           


Here is the initialization of the ADC, the interrupt mode is enabled assigning the ‘true’ value to the variable adcUserConfig.intEnable, 10bit resolution is selected by kAdcResolutionBitOf10or11, the hardware trigger is enabled and the continuous conversion disabled with adcUserConfig.hwTriggerEnable and adcUserConfig.continuousConvEnable, respectively. Moreover, the selected clock source is asynchronous, kAdcClkSrcOfAsynClk. After these comes the call to the function ADC16_DRV_Init that receives as parameters the ADC uiInstance being used and a pointer to the structure adcUserConfig that contains the configuration selected by the user.

The function ADC_TEST_InstallCallback installs the callback for the interrupt, its parameters are the uiInstance, the CHANNEL_0 from which will be received the interruption trigger and the name of the interruption handler function, MyADC1IRQHandler.

The configurations for the ADC reading channel are the selection of the channel number adcChnConfig.chnNum (in this case it is being used the CHANNEL_1), the differential mode is disabled with the variable adcChnConfig.diffEnable, the trigger interrupt is enable at adcChnConfig.intEnable and with adcChnConfig.chnMux the channel multiplexer for a/b channel is selected by kAdcChnMuxOfA.

Finally, the call to the function ADC16_DRV_ConfigConvChn receives the uiInstance number, the CHANNEL_0 for receiving the interrupt trigger and a pointer to the structure adcChnConfig that configures the ADC channel.

The ADC trigger source initialization is presented below

void init_trigger_source(uint32_t uiAdcInstance) {     lptmr_user_config_t lptmrUserConfig =     {         .timerMode = kLptmrTimerModeTimeCounter,         .freeRunningEnable = false,         .prescalerEnable = false, /* bypass prescaler */         .prescalerClockSource = kClockLptmrSrcMcgIrClk, /* use MCGIRCCLK */         .isInterruptEnabled = false     };      /* Init LPTimer driver */     LPTMR_DRV_Init(0, &lptmrUserConfig, &gLPTMRState);      /* Set the LPTimer period */     LPTMR_DRV_SetTimerPeriodUs(0, LPTMR_COMPARE_VALUE);      /* Start the LPTimer */     LPTMR_DRV_Start(0);      /* Configure SIM for ADC hw trigger source selection */     SIM_HAL_SetAdcAlternativeTriggerCmd(gSimBaseAddr[0], uiAdcInstance, true);     SIM_HAL_SetAdcPreTriggerMode(gSimBaseAddr[0], uiAdcInstance, kSimAdcPretrgselA);     SIM_HAL_SetAdcTriggerMode(gSimBaseAddr[0], uiAdcInstance, kSimAdcTrgSelLptimer); }          


The user configuration for the LPTMR is located at the structure lptmrUserConfig, here the LPTMR Time Count mode is selected by kLptmrTimerModeTimeCounter, the free running mode, the prescaler and the timer interrupt are disabled with freeRunningEnable, prescalerEnable and isInterruptEnbled, respectively. Furthermore, the LPTMR clock source is selected as the Internal Reference Clock with kClockLptmrSrcMcgIrClk.

The function LPTMR_DRV_Init receives as parameter the instance number, a pointer to the structure lptmrUserConfig that contains the user configurations and a pointer to the structure gLPTMRState with internal information of the LPTMR driver.

The function LPTMR_DRV_SetTimerPeriodUs set the corresponding timer period for the LPTMR, its parameters are the ADC instance and LPTMR_COMPARE_VALUE that saves the period value in us. The LPTMR_COMPARE_VALUE macro is located and can be set at the lptmr_trigger.c file. Moreover, the user will be able to change this period during the execution time at the Variable Watch section in the FreeMASTER project, modifying the value of LPTMR Interrupt Time (us) and setting the LPTMR Time Flag on 1.

LPTMR_DRV_Start starts the LPTMR and its only parameter is the ADC instance.                                          

Finally, there are three functions that configure the SIM for the ADC hardware trigger source selection; they receive as parameters the array initializer of SIM peripheral base addresses, gSimBaseAddr[0], and uiAdcInstance. The function SIM_HAL_SetAdcAlternativeTriggerCmd enables/disables the alternative conversion triggers; in this case it receives a true value, so it is enabled. Moreover, SIM_HAL_SetAdcPreTriggerMode selects the pre-trigger source; its third parameter is kSimAdcPretrgselA that corresponds to Pre-trigger A. The last one, SIM_HAL_SetAdcTriggerMode, selects the trigger source, so it’s receiving kSimAdcTrgSelLptimer.

The following code snippet shows the implemented algorithm to calculate the distance

void GetCurrentDistanceValue(uint32_t uiAvgAdc) {     static uint32_t sdwCurrentDistance = 0;      uint32_t dwm = 0;     uint32_t dwb = 0;      if((520 <= uiAvgAdc) && (uiAvgAdc < 840))     {       dwm = 641;       dwb = 683970;     }     else if((260 <= uiAvgAdc) && (uiAvgAdc < 519))     {       dwm = 1337;       dwb = 1011000;     }     else if((130 <= uiAvgAdc) && (uiAvgAdc < 259))     {       dwm = 2941;       dwb = 1423500;     }     sdwCurrentDistance = (dwb-(dwm*uiAvgAdc));     g_dwDistanceIntegers = (sdwCurrentDistance/10000);     g_dwDistanceTenths = ((sdwCurrentDistance - (g_dwDistanceIntegers*10000))/1000); }          


The implemented algorithm to calculate the distance is based on the division of the characteristic curve of the IR Sensor’s behavior in three different sections in order to approximate it to a linear behavior. Each line was generated from two different points. The first line is used when the uiAvgAdc value is between 520 and 840 (15 - 35 cm). The second one, for an uiAvgAdc value higher than 260 and lower than 519 (40 - 65 cm). And the last one, for uiAvgAdc values between 130 and 259 (70 - 100 cm). Depending on the calculated uiAvgAdc value, the slope (dwm) and the intersection with the y axis (dwb) change for each line.

  In order to make the demo compatible with different microcontrollers and IDEs, it was necessary to avoid the use of float variables to calculate the distance, so that the result could be printed on a console without problems. The real values of the slopes and intersections with the y-axis for each line were multiplied by 10000. After getting sdwCurrentDistance value it is divided into integers and tenths; to get the integers at g_dwDistanceIntegers, the current distance is divided by 10000 and the corresponding fraction for tenths is stored in g_dwDistanceTenths. As a result, the current distance value is printed combining the integers and tenths variables, avoiding the use of a float variable.


     The following graphic shows the characteristic curve and the three lines in which it was divided


Figure 4. Characteristic curve’s graphic

The application test’s results are shown in the following table

Table 2.PNG.png

1 The error for the Distance Measured values is approximately ± 0.5 cm

2 The ADC Average values have an error of approximately ± 5 units

Table 2. Test’s Results

Steps to include IR sensor software to KSDK

In order to include this demo in the KSDK structure, the files need to be copied into the correct place. The distance_measure_IRsensor folder should be copied into the <KSDK_install_dir>/demos folder.

If the folder is copied to a wrong location, paths in the project and makefiles will be broken. When the copy is complete you should have the following locations as paths in your system:

  • <KSDK_install_dir>/demos/distance_measure_IRsensor/iar
  • <KSDK_install_dir>/demos/distance_measure_IRsensor/kds
  • <KSDK_install_dir>/demos/distance_measure_IRsensor/src

In addition, to build and run the demo, it is necessary to download one of the supported Integrated Development Enviroment (IDE) by the demo:


   Once the project is opened in one of the supported IDEs, remember to build the KSDK library before building the project, if it was located at the right place no errors should appear, start a debug session and run the demo. The results of the distance measurement will be shown by UART on a console (use 115 200 as Baud rate) and at FreeMASTER, just as in the following example where the reflective object was located at 35 cm from the IR sensor:


Figure 5. Example of the distance measured being shown in a console


Figure 6. Example of the ADC Values obtained from the IR sensor monitored with FreeMASTER


Figure 7. Example of the distance measured results at FreeMASTER

FreeMASTER configuration

For visualizing the application’s result on FreeMASTER it is necessary to configure the corresponding type of connection for the FRDM-K64F:

1. Open FreeMaster.

2. Go to File/Open Project.

3. Open the Distance Measurement IR Sensor project from <KSDK_install_dir>/demos/distance_measure_IRsensor/ FreeMaster.

4. Go to Project/Options.

5. On the Comm tab, make sure the option ‘Plug-in Module’ is marked and select the corresponding type of connection.


Figure 8. Corresponding configurations FRDM-K64F’s connection at FreeMASTER

It is also necessary to select the corresponding MAP file for the IDE in which will be tested the demo, so:

6.  Go to the MAP Files tab.

7.  Select the MAP File for the IAR or the KDS project.

*Make sure that the default path matches with the one where is located the MAP file of the demo at your PC. If not, you can modify the path by clicking on the ‘…’ button (see Figure 9) and selecting the correct path to the MAP file:

  • <KSDK_install_dir>/demos/distance_measure_IRsensor/iar/frdmk64f/debug/distance_measure_IRsensor_frdmk64f.out
  • <KSDK_install_dir>/demos/distance_measure_IRsensor/kds/frdmk64f/Debug/distance_measure_IRsensor_frdmk64f.elf

8.  Click on ‘OK’ to save the changes.


Figure 9. Selection of the MAP File for each IDE supported by the demo

I hope this demo to be useful for your applications, enjoy!