This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: MSP432P401R
Tool/software: Code Composer Studio
Hello TI community
I plan to convert the analog inputs of 5 sensors using ADC14. In other words, I want to put this task in a function, readADC, and whenever the program called it, five conversions are done. The ADC14 initiation is as follows:
void initADC(void)
{
P5SEL0 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5; // ADC channels on A0, A1, A2,A3,A4
P5SEL1 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5;
ADC14->CTL0 = ADC14_CTL0_SHT0_1 | ADC14_CTL0_ON | ADC14_CTL0_SSEL_4 | ADC14_CTL0_CONSEQ_0 | ADC14_CTL0_SHP;
ADC14->CTL1 = ADC14_CTL1_RES_1;
}
And also the conversions are done as follows:
void readADC(void)
{
/*************************************************************************************************/
ADC14->CTL0 &= ~(ADC14_CTL0_ENC|ADC14_CTL0_SC);
ADC14->MCTL[0] |= ADC14_MCTLN_INCH_0;
ADC14->CTL0 |= ADC14_CTL0_ENC |ADC14_CTL0_SC ;
while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
sensor1= ADC14->MEM[0];
ADC14->CTL0 &= ~(ADC14_CTL0_ENC+ ADC14_CTL0_SC);
/*************************************************************************************************/
ADC14->MCTL[1] |= ADC14_MCTLN_INCH_1;
// ADC14->CTL1 |= ADC14_CTL1_CSTARTADD_1;
ADC14->CTL0 |= ADC14_CTL0_ENC |ADC14_CTL0_SC ;
while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
sensor2= ADC14->MEM[1];
ADC14->CTL0 &= ~(ADC14_CTL0_ENC+ ADC14_CTL0_SC);
/*************************************************************************************************/
ADC14->MCTL[2] |= ADC14_MCTLN_INCH_2;
ADC14->CTL0 |= ADC14_CTL0_ENC |ADC14_CTL0_SC ;
while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
sensor3= ADC14->MEM[2];
ADC14->CTL0 &= ~(ADC14_CTL0_ENC+ ADC14_CTL0_SC);
/*************************************************************************************************/
ADC14->MCTL[3] |= ADC14_MCTLN_INCH_3;
ADC14->CTL0 |= ADC14_CTL0_ENC |ADC14_CTL0_SC ;
while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
sensor4= ADC14->MEM[3];
ADC14->CTL0 &= ~(ADC14_CTL0_ENC+ ADC14_CTL0_SC);
/*************************************************************************************************/
ADC14->MCTL[4] |= ADC14_MCTLN_INCH_4;
ADC14->CTL0 |= ADC14_CTL0_ENC |ADC14_CTL0_SC ;
while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
sensor5= ADC14->MEM[5];
ADC14->CTL0 &= ~(ADC14_CTL0_ENC+ ADC14_CTL0_SC);
/*************************************************************************************************/
}
The problem I have is that the ADC14-> MEMx doesn't update and seems no conversions is done. Any idea where the problem is?
Thanks
Saber
> while (ADC14->CTL0 == ADC14_CTL0_BUSY); // Wait if ADC14 core is active
This condition will never be true. This won't cause the conversion not to complete, but you'll pick up the result before it's ready. Try:
> while (ADC14->CTL0 & ADC14_CTL0_BUSY); // Wait if ADC14 core is active
--------------------------------------------------------------------------------------------------------
> ADC14->MCTL[1] |= ADC14_MCTLN_INCH_1;
The ADC won't look at MCTL[1] and the others unless you change CSTARTADD=1 and so on. (It looks like you started to do that and then removed it?)
--------------------------------------------------------------------------------------------------------
Unsolicited: If you use CONSEQ=1, the ADC will do much of this work for you.
[Edit: I said something backwards the first time.]
Thanks Bruce for your reply.
The register you mentioned, CSTARTADD=1. I the datasheet, the register is defined as ADC14CSTARTADDx. My questions about this register are:
1-What does last letter,x, mean? Does it mean if I put x=0, it would put the conversion from INCH_0 to ADC14MEM[0] and so on?
2- And also, how can I change its value? I have written the format you can see below but the CCS gives me error on it.
ADC14->CTL1 = ADC14_CSTARTADD_0;
Do you have any idea how to resolve the issue?
Thanks
Saber
1) Setting (e.g.) CSTARTADD=1 directs the ADC to look at MCTL[1] for what to do; it will also store the result in MEM[1]. For a Sequence (CONSEQ=1 or 3) it will then look at MCTL[2] and store that result in MEM[2], and so on until one of the MCTL[] entries has the EOS bit set.
The MCTL[] register says what the INCH is. (You could have MCTL[0] request INCH_5 and then MCTL[1] request INCH_2, e.g. This is most useful if you have a "gap" in your channel numbering.)
2) Updating CSTARTADD is a bit clumsy. You first need to clear the field then set the new value, e.g.:
> ADC14->CTL1 = (ADC14->CTL1 & ~ADC14_CTL1_CSTARTADD_MASK) | (1 << ADC14_CTL1_CSTARTADD_OFS); // CSTARTADD=1
[I was expecting to find names like ADC14_CTL1_CSTARTADD_1, but didn't, ergo the "1<<".]
------------------------
Unsolicited: I'm sure you have a reason for doing it this way, but if you explain your goal there might be an easier way.
Thanks Bruce so much for your quick response and detailed information.
My goal is to measure the signals of 5 sensors. In contrast, I plan to have a function in the code and whenever the code called the function, the sensors' data would be digitized and their results are put into five variables. So you think there is easier way to do that?
Regards
Saber
If your goal is just to capture all 5 channels at once, I suggest CONSEQ=1 to get them all in a burst.
Schematically (abbreviating the names for clarity)
Once at the beginning:
CTL0 = CONSEQ_1|MSC|SHS_0|<the other good stuff> // Full sequence, all at once, started with SC MCTL[0] = INCH_0; MCTL[1] = INCH_1; MCTL[2] = INCH_2; MCTL[3] = INCH_3; MCTL[4] = INCH_4 | EOS; // A4 and End-Of-Sequence CTL0 |= ENC; // Enable Conversion and lock configuration
Then each time you want to sample:
CTL0 |= SC; // Start Conversion, which will do the whole sequence while (CTL0 & BUSY) /*EMPTY*/; // Wait for it to finish sensor0 = MEM[0]; // A0 result sensor1 = MEM[1]; // A1 result sensor2 = MEM[2]; sensor3 = MEM[3]; sensor4 = MEM[4];
This is somewhat like example adc14_06, but with CONSEQ=1 and no interrupts.
Thanks Bruce for your response!
I wrote the code as you mentioned. But it get stuck in the
while (CTL0 & BUSY) /*EMPTY*/; // Wait for it to finish
Seems the core would never be ready!
You can see the code below:
void main(void)
{
WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD; // stop watchdog timer
/***************************Configure Timer****************************************************************/
P5SEL0 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5;
P5SEL1 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5;
// Sampling time, S&H=16, ADC14 on
ADC14->CTL0 |= ADC14_CTL0_CONSEQ_1|ADC14_CTL0_MSC|ADC14_CTL0_SHS_0 | ADC14_CTL0_ON | ADC14_CTL0_SSEL_4;//<the other good stuff> // Full sequence, all at once, started with SC
ADC14->CTL1 |=ADC14_CTL1_RES_1;
ADC14->CTL1 = (ADC14->CTL1 & ~ADC14_CTL1_CSTARTADD_MASK) | (1 << ADC14_CTL1_CSTARTADD_OFS); // CSTARTADD=1
ADC14->MCTL[1] = 0x00000001; //A1 | AVSS, AVCC
ADC14->MCTL[2] = 0x00000002; //A2 | AVSS, AVCC
ADC14->MCTL[3] = 0x00000003; //A3 | AVSS, AVCC
ADC14->MCTL[4] = 0x00000004; //A4 | AVSS, AVCC
ADC14->MCTL[5] = 0x00000085; // A5 and End-Of-Sequence
ADC14->CTL0 |= ADC14_CTL0_ENC; // Enable Conversion and lock configuration
/*************************************************************************************************/
while(1)
{
ADC14->CTL0 |= ADC14_CTL0_SC; // Start Conversion, which will do the whole sequence
while (ADC14->CTL0 & ADC14_CTL0_BUSY); /*EMPTY*/ // Wait for it to finish
sensor1 = ADC14->MEM[1]; // A1 result
sensor2 = ADC14->MEM[2]; // A2 result
sensor3 = ADC14->MEM[3]; // A3 result
sensor4 = ADC14->MEM[4]; // A4 result
sensor5 = ADC14->MEM[5]; // A5 result
ADC14->CTL0 &= ~ADC14_CTL0_SC; // Start Conversion, which will do the whole sequence
}
}
Can you please have a look at it?
I appreciate it!
Thanks
Saber
I don't see ADC14_CTL0_SHP here (it was there before). I think its absence would cause the symptom you describe.
Unsolicited: SC clears by itself, so you don't need to explicitly clear it. (Though that doesn't hurt anything.)
Thanks Bruce.
The mentioned problem (the code get stuck in the while (ADC14->CTL0 & ADC14_CTL0_BUSY); ) was solved and the sampling is done. But one problem arose:
When I monitor the information of the sensors and change for example the state of one sensor, all the variables would change too. It seems, the ADC14MEMs registers are mixed/corrupted, etc. Do you have any idea how I can fix it? I'd appreciate it. My code is as below:
void initADC(void)
{
/****************************Configure ADC****************************************/
P5SEL0 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5;
P5SEL1 |= BIT1 + BIT2 + BIT3 + BIT4 + BIT5;
ADC14->CTL0 |= ADC14_CTL0_CONSEQ_1|ADC14_CTL0_MSC|ADC14_CTL0_SHS_0 | ADC14_CTL0_ON |ADC14_CTL0_SHP| ADC14_CTL0_SSEL_4;//<the other good stuff> // Full sequence, all at once, started with SC
ADC14->CTL1 |=ADC14_CTL1_RES_1;
ADC14->MCTL[1] = 0x00000001; //A1 | AVSS, AVCC
ADC14->MCTL[2] = 0x00000002; //A2 | AVSS, AVCC
ADC14->MCTL[3] = 0x00000003; //A3 | AVSS, AVCC
ADC14->MCTL[4] = 0x00000004; //A4 | AVSS, AVCC
ADC14->MCTL[5] = 0x00000085; // A5 and End-Of-Sequence
ADC14->CTL0 |= ADC14_CTL0_ENC; // Enable Conversion and lock configuration
}
void readADC(void)
{
ADC14->CTL0 |= ADC14_CTL0_SC; // Start Conversion, which will do the whole sequence
while (ADC14->CTL0 & ADC14_CTL0_BUSY); /*EMPTY*/ // Wait for it to finish
sensor1 = ADC14->MEM[1]; // A1 result
sensor2 = ADC14->MEM[2]; // A2 result
sensor3 = ADC14->MEM[3]; // A3 result
sensor4 = ADC14->MEM[4]; // A4 result
sensor5 = ADC14->MEM[5]; // A5 result
}
Regards
Saber
I don't see anything obviously wrong with the logic. I'm wondering if you're sampling (S/H) too fast:
1) Try increasing SHT0. The sample/hold capacitor is shared among the channels, and if you don't give it enough time to settle you could see "ghosting". There's a formula for SHT0/1 in TRM (SLAU356H) Sec 22.2.6.3, but just to see if it's the problem trying setting it fairly large, e.g. SHT0_6 (128 ADC clocks).
2) How fast are you running SMCLK? If you haven't touched it, it's 3MHz, which is within spec.Otherwise you should assure it's in spec per Data Sheet (SLAS826G) Table 5-28. Or just use MODCLK (SSEL_0) which was pretty much designed to run the ADC.
**Attention** This is a public forum