The goal of this example is to read all ADC inputs of Kinetis KL25 in a row without the need of using CPU core for switching channels and pins and reading individual values.
The FRDM-KL25 board features Kinetis MKL25Z128VLK4 microcontroller. This MCU contains a 16-bit AD converter with 16 inputs.
In Processor Expert there is available ADC_LDD component which can be used for measuring values on these pins. However, there is a limitation that some of the input pins (e.g. ADC0_SE4a and ADC0_SE4b) are muxed to same channel and ADC_LDD doesn’t allow to measure such two pins at once without additional mux-switching code. The MCU also does not provide an option of scanning through the ADC channels and the channels need to be switched by the user. To resolve the goal of measuring all inputs in a row the Peripheral Initialization components and DMA (Direct Memory Access) peripheral can be used.
Note: The archive with the example project is attached to this article.
The DMA in this example is used for controlling all the channel switching, pin mux selection and reading the results for series of measurement into a memory buffer.
Results are written to serial console (virtual serial port) provided by the FRDM board.
The Direct Memory Access (DMA) channels are configured for writing and reading ADC registers the following way:
DMA channel 1 changes the ADC pin group selection multiplexer (ADC0_CFG2 register) using values from memory array ChannelsCfg
DMA channel 2 selects the ADC channel and starts conversion (ADC0_SC1A register) using values from memory array ChannelsCfg2
The data for the DMA channel 1 a 2 are prepared in the ChannelsCfg and ChannelsCfg2 arrays prepared in memory and the DMA operates in the following cycle:
In the beginning, the DMA channel 1 transfer is started using software trigger. This selects the pin (a/b).
Then, DMA channel 2 is immediately executed because of enabled DMA channel linking. This configures the channel and starts the conversion.
After the conversion is complete, the result is read by DMA channel 0 and stored to results array. Channel linking executes the Channel 1 transfer and the cycle continues.
After all needed channels are measured (DMA byte counter reaches 0), the DMA Interrupt is invoked so the user code is notified.
See the following figure describing the process:
The application uses generated driver modules from the following Processor Expert components:
ConsoleIO properties setup
This component redirects printf command output to FRDM USB virtual serial port which is connected to UART0 pins PTA1/UART0_RX and PTA2/UART0_TX. The serial device, speed and pins are configured in inherited Serial_LDD component.
Init_ADC properties setup
The Init_ADC provides ADC initialization code with all channels enabled and set to single-ended.
The clock can be selected according to any valid value, according to the user needs.The same with HW average settings.
Compare functionality will not be used in this demo.
Pins configuration - all pins available on the board are enabled:
Interrupts, DMA and Triggering - Interrupts are disabled,DMA request is enabled. Triggering is disabled, as it’s not used in this demo project, However, the application could be extended to use it.
Init_DMA properties setup
The Init_DMA provides provides initialization code for the DMA.
Clock gate and DMA multiplexor are enabled:
DMA Channel 0
16-bit results are transferred from ADC0_RA register (see proprerty Data source / Address).
Transfer mode is Cycle-steal, which means that only one transaction is done per each external request.
The destination address initial value is not filled in the inspector because it's filled repeatedly in the application code.
Channel linking is set to trigger channel 1 after each transfer
DMA mux settings for the Channel 0 are enabled and ADC0_DMA_Request is selected, which is the signal from ADC when the conversion ends.
"DMA transfer done" interrupt for this channel is enabled. The ADCint ISR function will be called.
External request (request from ADC) is Enabled to start the transfer. Byte count will also be changed before every sequence
DMA Channel 1
DMA channel 1 changes the ADC pin group selection multiplexer (ADC0_CFG2 register) using values from memory array ChannelsCfg.
Please note that the source address initial value is not filled, will be set in the application code along with the Byte count value.
There is no HW trigger for this channel, it's set to be triggered by SW only (and by linking mechanism, which will be used).
The linking from this channel is set to trigger CH2 after the transfer.
No interrupt is enabled for this channel
DMA Channel 2
DMA channel 2 selects the ADC channel and starts conversion (ADC0_SC1A register) using values from memory array ChannelsCfg2.
No channel is linked after the transfer ends - No link.
No external channel request is selected, this channel transfer is triggered by linking from CH2.
It's used in the application code to provide delay to slow down console output.
The TPM0 counter is used with the period of approx. 350ms.
No interurpt is used.
Auto initialization is enabled.
The channels/pins to be measured are specified in the ChannelsCfg and ChannelsCfg2 arrays.
These arrays contains a list of pins to be measured, the order can be changed according to the user needs, the channels can even be measured multiple times.
The special value 0x1F stops the conversion.
// configuration array for channels - channel numbers. Should ends with 0x1F which stops conversion
// seconcdonfiguration array coreesponding to channels selecting A/B pins
// For example: 0 + PIN_A corresponds to the pin ADC0_SE0, 5 + PIN_5 selects the pin ADC0_SE5b
// You can use these arrays to reorder the measurement as you need