I have 5 A/D channels all various channels of ADC1. If I try to initialize any channel that is on the ADC1_SOURCE_AD19 or ADC1_SOURCE_AD20 the system comes back with a failed attempt. If I try ADC1_SOURCE_AD0 it works just fine. Problem is that I need AD19 and AD20 as that is where the hardware has the values..
I'm trying to single step through the fopen driver for the ADC to see where the error is.. but the IDE for the debugger keeps crashing on me.
#define MY_TRIGGER ADC_PDB_TRIGGER //Trigger Used for Every Channel// Logical channel init struct - ADC1_AD19 - EX_ANALOG_1 const ADC_INIT_CHANNEL_STRUCT Ex1_ch_param = { ADC1_SOURCE_AD19, // Physical ADC channel ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED, // Runs continuously after IOCTL trigger 1, // Number of samples in one run sequence 0, // Time offset from trigger point in us 100000, // Period in us (= 0.1 sec) 0x10000, // Scale range of result (not used now) 1, // Circular buffer size (sample count) MY_TRIGGER, // Logical trigger ID that starts this ADC channel &adcEvent, // lwevent Object ADC_DATA_READY_MASK // lwevent Mask to be set when complete. };// Logical channel init struct - ADC1_AD0 - Heat Seal const ADC_INIT_CHANNEL_STRUCT HeatSeal_ch_param = { ADC1_SOURCE_AD0, // Physical ADC channel ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED, // Runs continuously after IOCTL trigger 1, // Number of samples in one run sequence 0, // Time offset from trigger point in us 100000, // Period in us (= 0.1 sec) 0x10000, // Scale range of result (not used now) 1, // Circular buffer size (sample count) MY_TRIGGER, // Logical trigger ID that starts this ADC channel NULL, // lwevent Object 0 // lwevent Mask to be set when complete. }; // Open the ADC device adc = fopen(ADC_STR, (const char*)&adc_init); if (adc == NULL) { printf("\nADC_Task: Open ADC device failed!\n"); _task_block(); } // Open and Initialize the ADC Channels. adc_ex1 = fopen(EX1_STR, (const char*)&Ex1_ch_param); if (adc_ex1 == NULL) { printf("\nADC_Task: Open ADC channel for EX1 failed!\n"); //_task_block(); } // Open and Initialize the ADC Channels. adc_hs = fopen(HS_STR, (const char*)&HeatSeal_ch_param); if (adc_hs == NULL) { printf("\nADC_Task: Open ADC channel for Heat Seal failed!\n"); // _task_block(); } ......
Any thoughts on my ADC error or the crashing Debugger would be helpful?
FYI.. I'm using a K70 ad the P&E Multilink Universal Debugger under CodeWarrior 10.2 with MQX 3.8.
Thanks.
The LWADC driver in MQX v4.0 has been updated to support Kinetis. The LWADC driver is simpler to use than the Kinetis ADC driver, and it allows more than 2 channels per ADC. The LWADC driver does not use the PDB timer for hardware triggering of the ADC conversion like the ADC driver does.
The only Kinetis LWADC example provided in MQX v4.0 is for the TWR-K21D50M BSP, but the LWADC driver can be added to other Kinetis BSPs. The Kinetis LWADC example is configured to only scan 1 ADC channel for the potentiometer on the board. But with some simple changes, the BSP and example code can be modified to enable converting multiple channels.
In the BSP, modify twrk21d50m.h to add more ADC channel defines. In my example, I added two more channels for the Tower AN7 and AN6 signals. These are tied to ADC0_SE8 and ADC0_SE9 on the MCU. My twrk21d50m.h file is attached. Also, enable the BSPCFG_ENABLE_LWADC macro in user_config.h, then rebuild the BSP.
#define BSP_ADC_TWR_AN7 (ADC0_SOURCE_AD8) #define BSP_ADC_TWR_AN6 (ADC0_SOURCE_AD9)
In the example \Freescale_MQX_4_0\mqx\examples\lwadc, I found the application scanned all enabled channels in the BSP, but it did not change the channels in the continuous scan loop. I added calls to _lwadc_init_input() in the infinite scan loop in test.c, also attached. Now with the app rebuilt, it scans 3 ADC channels continuously.
printf("Monitoring ADC Inputs\n");
while (1) {
for (i=0;i<ELEMENTS_OF(adc_inputs);i++) {
/* DAS - Reinitialize to change channel */
if ( !_lwadc_init_input(&lwadc_inputs[i],adc_inputs[i].input) ) {
/* Failed to initialize this input. We will end up failing the reads below as well. */
printf("Failed to initialize ADC input %s\n",adc_inputs[i].name);
}
/* This waits until a new conversion is read on the channel */
if (_lwadc_wait_next(&lwadc_inputs[i])) {
if (_lwadc_read(&lwadc_inputs[i], &scaled) &&
_lwadc_read_raw(&lwadc_inputs[i], &raw)) {
/* Obtained data, is the change significant enough to display? */
delta = (raw>last[i])?raw-last[i]:last[i]-raw;
if (delta > max_delta) {
printf("%-30s = %04x (%d mv)\n",adc_inputs[i].name, raw,scaled);
last[i]=raw;
}
}
}
}
}
Hello Derek,
What is the right way of adding LWADC to other BSPs?
I have clone of bsp_twrk60f120m. I created the folder lwadc under Peripheral IO Drivers and added the follwing files:
lwadc_k21.c
lwadc_kadc_prv.h
lwadc_kadc.c
lwadc_kadc.h
lwadc.h
I also added this line in user_config.h
#define BSPCFG_ENABLE_LWADC | 1 |
But when I build the project, CW complains of many errors. The first of which is:
C:/Freescale/CW MCU v10.3/MCU/ARM_Tools/Command_Line_Tools/mwccarm|Compiler|Error
(C:\Freescale\Freescale_MQX_4_0\mqx\source\io\lwadc\lwadc_kadc.c|48|27|16|1793|16)
=static void _lwadc_restart(LWADC_STRUCT_PTR lwadc_ptr)
>illegal function definition
Could it be related to thi? In section 22.3 of the MQXIOUG.pdf it says "The platform specific header should be included before lwadc.h."
Which header file is specific to the K60?
Regards,
Joey
Hi Joey,
I don't know if you are still looking at this, but I was able to successfully implement lwadc for the TWRK20D72M MQX 4.0.1 bsp (https://community.freescale.com/thread/308825).
It's a lot of work and I had to reload MQX twice because I trashed the bsp(s) but it is possible and lwadc works quite well.
Maybe somebody at FSL can describe how to port in a driver like this easily.
myke
Hello joey81,
I suggest you to look for lwadc in another bsp to find out all places which you should change in your bsp.
Let's take an example from TWRPXN20 bsp to highlight all lwadc related declarations/definitions, there's init_lwadc file where is definition of lwadc structure, create this structure according to your board.
const LWADC_INIT_STRUCT lwadc0_init = { 0, LWADC_FORMAT_RIGHT_JUSTIFIED, BSP_PERI3_CLOCK, BSP_ADC_VREF_DEFAULT };
includes in bsp header file
#include <lwadc_mpxnxx.h>
#include <lwadc_mpxn20.h>
#include <lwadc.h>
bsp_prv header file declares extern structure
extern const LWADC_INIT_STRUCT lwadc0_init;
There's conditionaly compiled code in init_bsp code file
#if BSPCFG_ENABLE_LWADC
#if BSPCFG_ENABLE_LWADC0
_lwadc_init(&lwadc0_init);
#endif
#endif
Last file is the board header which should contain all macros which are used in the driver (check LWADC DRIVER CONFIGURATION). The next step is to customize lwadc driver ( create your own lwadc_k60 file because I believe there is more than just one ADC module).
Regards,
MartinK
Hi All,
I played with ADC in MQX awhile back. ZIP attached. It is not elegant code but in general what it is doing is the following:
- Infinite loop in main() that is checking to see if a ADC task is running or not. If not it then creates one. Since the ADC task is higher priority it will run to completion and terminate.
- The ADC task that is created temporarily is passed a “channel #” (it really is an index to the adc_channel_paramx definitions).
- The ADC task will open the appropriate ADC module and channel, get a sample, place sample in global variable (ADC_RESULT_STRUCT data and print it to the terminal.
- The ADC task will close the channel and module, then terminate.
I envision being able to create a table of the adc_channel_paramx’s and using DMA interrupts with ADC interrupts to more autonomously and dynamically collect ADC samples. I just haven’t gotten there yet time wise.
Customer is correct that it is only two samples per ADC module that can occur. Therefore the above solution.
Note when debugging ADC code you really have to let it fly. Halting the processor does not halt the ADC and once you halt while it is trying to sample it stops trigger properly. I think that has to deal with the debugger reading ADC register that then clears a flag you don’t want cleared.
Hope this helps.
Regards,
David
Hello DavidS,
Thanks for the sample code.. In reviewing I notice that your version of init_gpio.c Version 3.8.24.0 OCt 7-2011.. actually has AD19 and AD20 implemented in the manner I suggested in my above reply.. Which K device was that from?
Also, is there a significance to turning ON and OFF the clock module as you do in the _bsp_adc_io_init? Is that to "reset" the modules so that you can reiniitialize for the next channel setup?
Thanks for your help...
One More thing..
Is it true that the MQX driver can only handle 2 channels per ADC block..?
Can I open more than one block for the same hardware resource?
ADC_MAX_CHANNELS is set to a (2) inside the adc.c files.
Hello Ali2006,
It's not drawback of MQX but hardware. Therefore it's set to 2.
Open file init_gpio in K70 BSP folder. There are declared 2 adc conversion tables (adc0, adc1). They don't have channels 19 and 20 implemented. I checked K70 reference manual, those 2 channels are not available:
from adc1:
ADC_SIG_NA, //19 not implemented
ADC_SIG_NA, //20 not implemented
This is the cause of opening error.
Regards,
MartinK
Hello Kojto,
As I read the K70 Reference manual, the K70 in the 256BGA package is supposed to have 4 ADC modules.. each with the ability to select up to 32 different sources. I have looked again at the ADC1 channel assigments on page 140/141 of the reference manual section 3.7.1.4 and I should be able to select channel AD19 and get input signal ADC1_DM0.. and AD19 should give me ADC1_DM1.
But.. I have now also looked at the init_gpio as you mentioned and do see the AD19 and AD20 are not implemented. I can see that they probably left them off because as they can be associated with differential channels.. but they are available for use singled ended.. (Unless I'm misreading the manual?)
Do you.. or anyone else, see any reason why I couldn't implement these signals by modifying the init_gpio module to return the ADC_SIG_NC for them.. since they are on pins that "default" to analog? I know I'm just asking for future problems.. but this seems like a start anyway.. Does anyone know of any other pitfalls before I get started with this approach? .. Or should I just abandon MQX driver and write my own.?
Thanks for your help..
Hello,
the question about only 2 conversion of kinetis ADC was asked here before. It's limited by ADCx_SC1x registers. There are only 2, each one for each conversion, therefore number is set to 2 in MQX ADC driver for K70. Read 39.3.1 chapter for more information.
I checked the package of our K70 tower and there should be available those 2 channels ADC. Even some others are not implemented but present in the MCU. It is going to be fixed.
What you can do right now is to enable those channels by changing adc tables in init_gpio code file. I suggest you to back up the file before you do any change just for future reference if anything goes wrong. Let us know the result.
Regards,
MartinK