Hi all,
I am an absolute newbie to embedded programming world. I downloaded the code sample package and am trying to understand the AdcDemoWithDMA that came with it. I am using Keil.
Question 1: I understood it's demo-ing Analog to Digital conversion, but from what kind of analog input? and output to where?
Question 2: This is a piece of code from "dma0_init". I can barely understand any of them. I am particularly confused by the bit-wise operations and the thousands of "masks" involved. Can anybody pick some examples and explain what those "masks" really do?
Question 3: are there more fundamental tutorials? I have read the quick start package, but as you guys have probably realized, I still need more help....
Thanks a lot!
void Dma0_init(void)
{
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
// Config DMA Mux for UART0 operation
// Disable DMA Mux channel first
DMAMUX0_CHCFG0 = 0x00;
// Clear pending errors and/or the done bit
if (((DMA_DSR_BCR0 & DMA_DSR_BCR_DONE_MASK) == DMA_DSR_BCR_DONE_MASK)
| ((DMA_DSR_BCR0 & DMA_DSR_BCR_BES_MASK) == DMA_DSR_BCR_BES_MASK)
| ((DMA_DSR_BCR0 & DMA_DSR_BCR_BED_MASK) == DMA_DSR_BCR_BED_MASK)
| ((DMA_DSR_BCR0 & DMA_DSR_BCR_CE_MASK) == DMA_DSR_BCR_CE_MASK))
DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;
// Set Source Address (this is the UART0_D register
DMA_SAR0 = (unsigned int)&ADC0_RA;
// Set BCR to know how many bytes to transfer
DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(10);
// Clear Source size and Destination size fields.
DMA_DCR0 &= ~(DMA_DCR_SSIZE_MASK
| DMA_DCR_DSIZE_MASK
);
// Set DMA as follows:
// Source size is byte size
// Destination size is byte size
// D_REQ cleared automatically by hardware
// Destination address will be incremented after each transfer
// Cycle Steal mode
// External Requests are enabled
// Asynchronous DMA requests are enabled.
DMA_DCR0 |= (DMA_DCR_SSIZE(2)
| DMA_DCR_DSIZE(2)
| DMA_DCR_DMOD(0)
| DMA_DCR_D_REQ_MASK
| DMA_DCR_DINC_MASK
// | DMA_DCR_SINC_MASK // no change source address
| DMA_DCR_CS_MASK
| DMA_DCR_EINT_MASK
| DMA_DCR_ERQ_MASK
| DMA_DCR_LINKCC(2)
| DMA_DCR_LCH1(2)
// | DMA_DCR_EADREQ_MASK
);
// Set destination address
DMA_DAR0 = (unsigned int)&m_uiADCResultBuff[0];
// Enables the DMA channel and select the DMA Channel Source
DMAMUX0_CHCFG0 = DMA_REQUEST_SOURCE_ADC0; //DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x31); //0xb1;
DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK;
enable_irq(0);
}
Hi,
In order to understand the Projects you need to know what is being written to the registers. All the masks there are already defined, try to find the definition for each mask and check its value. Also you need to look in the Reference Manual for KL05 and see the registers and their fields.
You can find the RM here: http://cache.freescale.com/files/32bit/doc/ref_manual/KL05P48M48SF1RM.pdf?fsrch=1&WT_TYPE=Reference%...
I will give you an example:
DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;
The name of the register is: DMA_DSR_BCRn (Section 23.3.3 in RM)
#define DMA_DSR_BCR_DONE_MASK 0x1000000u
It is writng 0x1000000 to register DMA_DSR_BCR0.
Hope this helps.
Hi Adrian, Thanks a lot for your detailed answer. It was extremely helpful. I have better understanding about the registers now. Though I still have more questions about the overall workflow of the Analog to Digital Converter.
I extracted a few lines of code here.
Question 1:
How did they define those channels. From the reference manual, I found the channel address goes as things like "4003_B000". But from the source code, where do those "0x0d|0x40" come from?
Question 2:
Can you explain how the main function works? I don't quite understand the difference between "m_bDMA2Flag" and "m_bDMA0Flag"
Question 3:
Can you explain what method "StartADCScan" does? I don't quite understand how DMA_DCR2 |= DMA_DCR_START_MASK; does any scanning...
I didn't include the implementation of
void Dma0_init(void);
void Dma2_init(void);
void DMA0_IRQHandler(void);
void DMA2_IRQHandler(void);
void StartADCScan( void );
But if you need them I will include them. Thanks again!
#include "common.h"
#include "adc.h"
#ifdef CMSIS
#include "start.h"
#endif
#define DMA_REQUEST_SOURCE_ADC0 40
#define DMA_REQUEST_SOURCE_ALWAYS 60
uint8_t m_uiADCChannelBuff[6] = {
0x0d|0x40, //channel 0x0d -- external channel 13
0x1d|0x40, //channel 0x0d -- Vrefh
0x1e|0x40, //channel 0x1e -- Vrefl
0x1d|0x40, //channel 0x1d -- Vrefh
0x1a|0x40, //channel 0x1a -- temperature sensor
0x1f|0x40 //channel disable,last time,disable ADC channel to avoid to generate new ADC interrupt.
};
uint16_t m_uiADCResultBuff[8] = {0,0,0,0,0,0,0};
uint8_t m_bDMA0Flag;
uint8_t m_bDMA2Flag;
void Dma0_init(void);
void Dma2_init(void);
void DMA0_IRQHandler(void);
void DMA2_IRQHandler(void);
void StartADCScan( void );
/********************************************************************/
int main (void)
{
uint8_t i;
uint32_t uiSum;
printf("\nRunning the AdcDemoWithDMA project.\n");
InitADC();
if( ADC_Cal(ADC0_BASE_PTR) )
{
printf("ADC calibration fail!\n");
}
Dma0_init();
Dma2_init();
// disable ADC module
ADC0_SC1A = 0x1f;
// enable DMA transfer for ADC module
ADC0_SC2 |= ADC_SC2_DMAEN_MASK;
printf("input char 's', trigger new ADC scan with DMA...\n");
while(1)
{
if( m_bDMA0Flag )
{
m_bDMA0Flag = 0;
printf("ADC conversion success!\n");
uiSum = 0;
for(i=0;i<5;i++)
{
printf("0x%x,",m_uiADCResultBuff[i]);
uiSum += m_uiADCResultBuff[i];
}
printf("\n");
// printf("new value for input voltage is: 0x%x\n",uiSum);
}
if( m_bDMA2Flag )
{
m_bDMA2Flag = 0;
//printf("DMA channel 2 transfer completed!\n");
}
if( UART0_S1 & UART0_S1_RDRF_MASK )
{
if( 's' == UART0_D )
{
StartADCScan();
}
}
}
}
void StartADCScan( void )
{
// write start to DMA channel to start DMA transfer, so that write channel data to ADC_SCA
DMA_DCR2 |= DMA_DCR_START_MASK;
}