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.
Tool/software: TI-RTOS
Dear TI-Experts,
I want to learn more about TI-RTOS drivers in the SimpleLink software package. As far as I understand those are called TI-Drivers (and support also FreeRTOS and NoRTOS). I could only find lots of examples (thanks for those) and doxygen documentation. I'm missing a user guide. I got the impression, that SimpleLink Academy should fill the gap, but I couldn't find anything related to ADC usage.
Could you send me helpful links?
For the driverlib I'm also missing a user guide like "TivaWare™ Peripheral Driver Library User Guide" SPMU298D.
Could you send me helpful links?
Are driverlib for MSP432E411Y and TM4C129 similar enough to use SPMU298D instead?
Hello Sven,
Sven Probst said:I want to learn more about TI-RTOS drivers in the SimpleLink software package.
The Documentation Overview Page and the SimpleLink Academy are the best starting points to understand TI-Drivers.
Sven Probst said:As far as I understand those are called TI-Drivers (and support also FreeRTOS and NoRTOS)
Your understanding is right.
Sven Probst said:I'm missing a user guide. I got the impression, that SimpleLink Academy should fill the gap, but I couldn't find anything related to ADC usage.
Did you already look at the SimpleLink Academy module called "Project 0" under TI-Drivers? It introduces the concepts of TI-Drivers using ADC TI-Driver.
The Documentation Overview Page will lead you to the "TI Drivers Runtime APIs (doxygen)" page. If you click on ADC.h file, the top section has an overview on the operation of the driver along with implementation specifics.
We don't have any User's Guide for the TI-Drivers.
Can you list a few things that you think are missing from the above mentioned documentation? I will provide this feedback to our internal teams so that we can improve the documentation.
Sven Probst said:For the driverlib I'm also missing a user guide like "TivaWare™ Peripheral Driver Library User Guide" SPMU298D.
Thanks for pointing that out. I will file a bug so that we can add it in the future releases.
Sven Probst said:Are driverlib for MSP432E411Y and TM4C129 similar enough to use SPMU298D instead?
Yes they are similar. We would recommend using the TI-Drivers as they are RTOS aware, portable etc. Use driverlib for fine tuning the TI-Driver or if you think the TI-Drivers won't work for your application.
If you do decide to use driverlib API, we would really appreciate if you can provide feedback as to why you don't want to use TI-Drivers.
Hope this information helps!
Thanks,
Sai
Hello Sai,
thank you very much for your explanation.
For convenience of other forum users I added two files containing definitions for 20 ADCs of the MSP-EXP432E401Y. It is using 2 sequencers of ADC 0 and one of ADC 1. The ADC entries in "MSP_EXP432E401Y.c" have to get removed.
Following code fragment shows usage:
#include "Board2.h"
...
/* structure to hold argument to callback function */ typedef struct adcArgStruct { uint8_t id; } adcArgStruct_t; typedef adcArgStruct_t adcArgStructArray_t[3]; /* a result is the average of SAMPLES_PER_CHANNEL (already hardware averaged) samples */ #define RESULT_SAMPLERATE 10 // Hz /* Identifier used in callback function to distinguish between sequencers */ #define ADCBUF0_SQ0_ID 3 #define ADCBUF0_SQ1_ID 5 #define ADCBUF1_SQ0_ID 7 /* channels used in each sequencer */ #define ADCBUF0_SQ0_USED_CHANNELS 8 #define ADCBUF0_SQ1_USED_CHANNELS 4 #define ADCBUF1_SQ0_USED_CHANNELS 8 #define TOTAL_USED_CHANNELS (ADCBUF0_SQ0_USED_CHANNELS+ADCBUF0_SQ1_USED_CHANNELS+ADCBUF1_SQ0_USED_CHANNELS) /* number of samples to calculate software average on (sample rate as specified in call of ADCBuf_open) * - we use additional hardware averaging by ADCs at ADC conversion rate (1MS/s) */ #define SAMPLES_PER_CHANNEL 12 #define ADCBUF0_SQ0_BUFFERSIZE (ADCBUF0_SQ0_USED_CHANNELS*SAMPLES_PER_CHANNEL) #define ADCBUF0_SQ1_BUFFERSIZE (ADCBUF0_SQ1_USED_CHANNELS*SAMPLES_PER_CHANNEL) #define ADCBUF1_SQ0_BUFFERSIZE (ADCBUF1_SQ0_USED_CHANNELS*SAMPLES_PER_CHANNEL) /* define buffers for continuous conversion mode of driver (double buffer approach via DMA) */ uint16_t bufferAdc0Sq0Ping[ADCBUF0_SQ0_BUFFERSIZE]; uint16_t bufferAdc0Sq0Pong[ADCBUF0_SQ0_BUFFERSIZE]; uint16_t bufferAdc0Sq1Ping[ADCBUF0_SQ1_BUFFERSIZE]; uint16_t bufferAdc0Sq1Pong[ADCBUF0_SQ1_BUFFERSIZE]; uint16_t bufferAdc1Sq0Ping[ADCBUF1_SQ0_BUFFERSIZE]; uint16_t bufferAdc1Sq0Pong[ADCBUF1_SQ0_BUFFERSIZE]; /* temporal buffer for channel separation in callback function */ int32_t tempBuffer[SAMPLES_PER_CHANNEL]; /* array to hold averaged results of all channels (ADC0 Sq0, ADC0 Sq1, ADC1 Sq0) */ uint16_t ADC_uC_result[TOTAL_USED_CHANNELS]; /* array to hold arguments to callback functions */ adcArgStructArray_t args; /* * Callback function of ADC 0. This function is called whenever a buffer is full. * All ADC-DMA interrupts (2 per ADC) should have same priority, * thus one callback function for both ADCs should be sufficient (no preemption)? */ void adcBuf0Callback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion, void *completedADCBuffer, uint32_t completedChannel) { uint_fast16_t channelIdx, sampleReadIdx, sampleWriteIdx; uint16_t *completedBuffer = (uint16_t *) completedADCBuffer; adcArgStruct_t* argument; uint8_t id; argument = (adcArgStruct_t*)(conversion->arg); id = argument->id; if (id == ADCBUF0_SQ0_ID) { for (channelIdx = 0; channelIdx < ADCBUF0_SQ0_USED_CHANNELS; channelIdx++) { /* data order: ch0s0, ch1s0, ..., chNs0, ch0s1, ch1s1, ..., chNs1, ... */ sampleReadIdx = channelIdx; /* copy all samples of one channel into one buffer */ for (sampleWriteIdx = 0; sampleWriteIdx<SAMPLES_PER_CHANNEL; sampleWriteIdx++) { tempBuffer[sampleWriteIdx] = (int32_t)completedBuffer[sampleReadIdx]; sampleReadIdx += ADCBUF0_SQ0_USED_CHANNELS; } /* perform sample processing (averaging) */ ADC_uC_result[channelIdx] = (uint16_t)average(tempBuffer, SAMPLES_PER_CHANNEL); } } else { for (channelIdx = 0; channelIdx < ADCBUF0_SQ1_BUFFERSIZE; channelIdx++) { // ... } } } /* callback function of ADC 1 * all ADC-DMA interrupts (2 per ADC) should have same priority, * thus one callback function for both ADCs should be sufficient (no preemption)? */ void adcBuf1Callback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion, void *completedADCBuffer, uint32_t completedChannel) { // ... } /* * ======== mainThread ======== */ void *mainThread(void *arg0) { ADCBuf_Handle adcBuf0,adcBuf1; ADCBuf_Params adcBufParams; ADCBuf_Conversion conversionParamADCbuf0Sq0[ADCBUF0_SQ0_USED_CHANNELS]; ADCBuf_Conversion conversionParamADCbuf0Sq1[ADCBUF0_SQ1_USED_CHANNELS]; ADCBuf_Conversion conversionParamADCbuf1Sq0[ADCBUF1_SQ0_USED_CHANNELS]; /* Call driver init functions */ ADCBuf_init(); /* Set up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS */ ADCBuf_Params_init(&adcBufParams); adcBufParams.callbackFxn = adcBuf0Callback; adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS; adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK; adcBufParams.samplingFrequency = RESULT_SAMPLERATE*SAMPLES_PER_CHANNEL; adcBuf0 = ADCBuf_open(Board_ADCBUF0, &adcBufParams); /* same parameters but different callback function for ADC 1 */ adcBufParams.callbackFxn = adcBuf1Callback; adcBuf1 = ADCBuf_open(Board_ADCBUF1, &adcBufParams); /* define ADC clock as 16MHz -> conversion rate = 1MSps at fPLL = 480MHz; ADCs share same clock, thus setting ADC 0 only */ ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, (480/16)); /* enable hardware averaging of 32 consecutive ADC samples taken at conversion rate */ ADCHardwareOversampleConfigure(ADC0_BASE,32); ADCHardwareOversampleConfigure(ADC1_BASE,32); /* set identifier values in array of arguments for callback functions */ args[0].id = ADCBUF0_SQ0_ID; args[1].id = ADCBUF0_SQ1_ID; args[2].id = ADCBUF1_SQ0_ID; /* Configure the conversion struct for all channels on ADCBuf0 sequencer 0 */ uint8_t chIdx; for (chIdx = 0; chIdx<ADCBUF0_SQ0_USED_CHANNELS; chIdx++) { conversionParamADCbuf0Sq0[chIdx].arg = &args[0]; conversionParamADCbuf0Sq0[chIdx].sampleBuffer = NULL; conversionParamADCbuf0Sq0[chIdx].sampleBufferTwo = NULL; conversionParamADCbuf0Sq0[chIdx].samplesRequestedCount = ADCBUF0_SQ0_BUFFERSIZE; } /* first channel entry takes buffer pointer */ conversionParamADCbuf0Sq0[0].sampleBuffer = bufferAdc0Sq0Ping; conversionParamADCbuf0Sq0[0].sampleBufferTwo = bufferAdc0Sq0Pong; conversionParamADCbuf0Sq0[0].adcChannel = Board_ADCBUF0CHANNEL0; conversionParamADCbuf0Sq0[1].adcChannel = Board_ADCBUF0CHANNEL1; conversionParamADCbuf0Sq0[2].adcChannel = Board_ADCBUF0CHANNEL2; conversionParamADCbuf0Sq0[3].adcChannel = Board_ADCBUF0CHANNEL3; conversionParamADCbuf0Sq0[4].adcChannel = Board_ADCBUF0CHANNEL4; conversionParamADCbuf0Sq0[5].adcChannel = Board_ADCBUF0CHANNEL5; conversionParamADCbuf0Sq0[6].adcChannel = Board_ADCBUF0CHANNEL6; conversionParamADCbuf0Sq0[7].adcChannel = Board_ADCBUF0CHANNEL7; /* Configure the conversion struct for all channels on ADCBuf0 sequencer 1 */ for (chIdx = 0; chIdx<ADCBUF0_SQ1_USED_CHANNELS; chIdx++) { conversionParamADCbuf0Sq1[chIdx].arg = &args[1]; conversionParamADCbuf0Sq1[chIdx].sampleBuffer = NULL; conversionParamADCbuf0Sq1[chIdx].sampleBufferTwo = NULL; conversionParamADCbuf0Sq1[chIdx].samplesRequestedCount = ADCBUF0_SQ1_BUFFERSIZE; } /* first channel entry takes buffer pointer */ conversionParamADCbuf0Sq1[0].sampleBuffer = bufferAdc0Sq1Ping; conversionParamADCbuf0Sq1[0].sampleBufferTwo = bufferAdc0Sq1Pong; conversionParamADCbuf0Sq1[0].adcChannel = Board_ADCBUF0CHANNEL8; conversionParamADCbuf0Sq1[1].adcChannel = Board_ADCBUF0CHANNEL9; conversionParamADCbuf0Sq1[2].adcChannel = Board_ADCBUF0CHANNEL10; conversionParamADCbuf0Sq1[3].adcChannel = Board_ADCBUF0CHANNEL11; /* Configure the conversion struct for all channels on ADCBuf1 sequencer 0 */ for (chIdx = 0; chIdx<ADCBUF1_SQ0_USED_CHANNELS; chIdx++) { conversionParamADCbuf1Sq0[chIdx].arg = &args[2]; conversionParamADCbuf1Sq0[chIdx].sampleBuffer = NULL; conversionParamADCbuf1Sq0[chIdx].sampleBufferTwo = NULL; conversionParamADCbuf1Sq0[chIdx].samplesRequestedCount = ADCBUF1_SQ0_BUFFERSIZE; } /* first channel entry takes buffer pointer */ conversionParamADCbuf1Sq0[0].sampleBuffer = bufferAdc1Sq0Ping; conversionParamADCbuf1Sq0[0].sampleBufferTwo = bufferAdc1Sq0Pong; conversionParamADCbuf1Sq0[0].adcChannel = Board_ADCBUF1CHANNEL0; conversionParamADCbuf1Sq0[1].adcChannel = Board_ADCBUF1CHANNEL1; conversionParamADCbuf1Sq0[2].adcChannel = Board_ADCBUF1CHANNEL2; conversionParamADCbuf1Sq0[3].adcChannel = Board_ADCBUF1CHANNEL3; conversionParamADCbuf1Sq0[4].adcChannel = Board_ADCBUF1CHANNEL4; conversionParamADCbuf1Sq0[5].adcChannel = Board_ADCBUF1CHANNEL5; conversionParamADCbuf1Sq0[6].adcChannel = Board_ADCBUF1CHANNEL6; conversionParamADCbuf1Sq0[7].adcChannel = Board_ADCBUF1CHANNEL7; /* check ADCs to open correctly */ if (!adcBuf0){ /* AdcBuf did not open correctly. */ while(1); } if (!adcBuf1){ /* AdcBuf did not open correctly. */ while(1); } /* Start converting ADC 0 sequencer 0. */ if (ADCBuf_convert(adcBuf0, conversionParamADCbuf0Sq0, ADCBUF0_SQ0_USED_CHANNELS) != ADCBuf_STATUS_SUCCESS) { /* Did not start conversion process correctly. */ while(1); } /* Start converting ADC 0 sequencer 1. */ if (ADCBuf_convert(adcBuf0, conversionParamADCbuf0Sq1, ADCBUF0_SQ1_USED_CHANNELS) != ADCBuf_STATUS_SUCCESS) { /* Did not start conversion process correctly. */ while(1); } /* Start converting ADC 1 sequencer 0. */ if (ADCBuf_convert(adcBuf1, conversionParamADCbuf1Sq0, ADCBUF1_SQ0_USED_CHANNELS) != ADCBuf_STATUS_SUCCESS) { /* Did not start conversion process correctly. */ while(1); } /* * Go to sleep in the foreground thread forever. The data will be collected * by callback functions */ while(1) { sleep(1000); } }
**Attention** This is a public forum