Hi everyone,
as you can guess from the title, I'm trying to implement the operation of the ADC in the TI-RTOS, since there are no libraries of this peripheral for TIVA devices.
FYI, I am using CCS v12.1.0 with the TM4C123GXL eval kit.
I have already downloaded the TIRTOS for TivaC v2.16.00.08 and I am able to use all the functionalities correctly. I saw in other post how to add the correct version of the xdc_tool.
I also use correctly GPIO, UART, Timers etc.
My objective is to enable the interrupt from the ADC sequencer0, generating an hwi and then store the data in a global variable.
When I saw that ADC lib is missing, the first try was to use a timer, generating a hwi and, usind the TIVA driverlib API, I was able to read the value correctly. Then, I wanna try to create the "TIRTOS for Tiva" part of the lib by myself, to use ADC API with a custom board in the future.
Now, I have already seen that in the forum there are posts related to ADC but some questions are unresolved or answers aren't exaustive and almost all posts are for MSP or CC microcontrollers
that have already the implemantation of ADC.
I start from the "empty" example for tirtos.
Firstly I've added in the "EK-TM4C123GXL.c" file the following:

In the "EK-TM4C123GXL.h" file I add the following:
/*!
* @def EK_TM4C123GXL_ADCName
* @brief Enum of ADCs on the EK_TM4C123GXL dev board
*/
typedef enum EK_TM4C123GXL_ADCName {
EK_TM4C123GXL_ADC0 = 0,
EK_TM4C123GXL_ADCCOUNT
} EK_TM4C123GXL_ADCName;
extern void EK_TM4C123GXL_initADC(void);
I've tryed to create by myself ADC.h and ADC.c files, observing ADC source and header files found online for MSP or CC microcontrollers, i attach the files below.
myADC.h/*
* ADC.c
*
* Created on: 10 feb 2023
* Author: marika
*/
/*
* Copyright (c) 2016-2019, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ======== ADC.c ========
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <myADC.h>
#include <myADCTiva.h>
#include <driverlib/adc.h>
/* Externs */
extern const ADC_Config ADC_config[];
/* Used to check status and initialization */
static int ADC_count= -1;
/* Default ADC parameters structure */
const ADC_Params ADC_defaultParams = {//TO CHECK
(uintptr_t) NULL /* custom */
};
/*
* ======== ADC_close ========
*/
void ADC_close(ADC_Handle handle)
{
handle->fxnTablePtr->closeFxn(handle);
}
/*
* ======== ADC_control ========
*/
int ADC_control(ADC_Handle handle, unsigned int cmd, void *arg)
{
return (handle->fxnTablePtr->controlFxn(handle, cmd, arg));
}
/*
* ======== ADC_init ========
*/
void ADC_init(void)
{
if (ADC_count == -1) {
/* Call each driver's init function */
for (ADC_count = 0; ADC_config[ADC_count].fxnTablePtr != NULL; ADC_count++) {
ADC_config[ADC_count].fxnTablePtr->initFxn((ADC_Handle)&(ADC_config[ADC_count]));
}
}
}
/*
* ======== ADC_open ========
*/
ADC_Handle ADC_open(unsigned int index, ADC_Params *params)
{
ADC_Handle handle;
if (index >= ADC_count) {
return (NULL);
}
/* If params are NULL use defaults */
if (params == NULL) {
params = (ADC_Params *) &ADC_defaultParams;
}
/* Get handle for this driver instance */
handle = (ADC_Handle)&(ADC_config[index]);
return (handle->fxnTablePtr->openFxn(handle, params));
}
/*
* ======== ADC_Params_init ========
*/
void ADC_Params_init(ADC_Params *params)
{
*params = ADC_defaultParams;
}
At the same way, I created additionally 2 files (myADCTiva.h/c) as attached below.
myADCTiva.h/*
* myADCTiva.c
*
* Created on: 14 feb 2023
* Author: nicol
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <xdc/runtime/Assert.h>
#include <xdc/runtime/Diags.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Types.h>
#include <myADCTiva.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>
#include <inc/hw_memmap.h>
#include <inc/hw_ints.h>
#include <inc/hw_types.h>
#include <driverlib/adc.h>
#include <inc/hw_sysctl.h>
#include <driverlib/sysctl.h>
/* ADCTiva functions */
void ADCTiva_close(ADC_Handle handle);
int ADCTiva_control(ADC_Handle handle, unsigned int cmd, void *arg);
void ADCTiva_init(ADC_Handle handle);
ADC_Handle ADCTiva_open(ADC_Handle handle, ADC_Params *params);
/* ADC function table for ADCTiva implementation */
const ADC_FxnTable ADCTiva_fxnTable = {
ADCTiva_close,
ADCTiva_control,
ADCTiva_init,
ADCTiva_open
};
/*
* ======== ADCTiva_close ========
*/
void ADCTiva_close(ADC_Handle handle){
ADCTiva_Object *object = handle->object;
ADCTiva_HWAttrs const *hwAttrs = handle->hwAttrs;
/* Disable ADC and interrupts. */
ADCIntDisable(hwAttrs->baseAddr, 0);
ADCSequenceDisable(hwAttrs->baseAddr, 0);
Hwi_destruct(&(object->hwi));
Semaphore_destruct(&(object->adcSem));
object->isOpen = false;
Log_print1(Diags_USER1, "ADC:(%p) closed", hwAttrs->baseAddr);
}
/*
* ======== ADCCTiva_control ========
* @pre Function assumes that the handle is not NULL
*/
int ADCTiva_control(ADC_Handle handle, unsigned int cmd, void *arg)
{
/* No implementation yet */
return (ADC_STATUS_UNDEFINEDCMD);
}
/*
* ======== ADCTiva_hwiFxn ========
* Hwi interrupt handler to service the ADC peripheral
*
* The handler is a generic handler for a ADC object.
*/
static void ADCTiva_hwiFxn(UArg arg){
/* Get the pointer to the object and hwAttrs */
ADCTiva_Object *object = ((ADC_Handle)arg)->object;
ADCTiva_HWAttrs const *hwAttrs = ((ADC_Handle)arg)->hwAttrs;
// uint32_t status;
/* Clear interrupts */
// status=ADCIntStatus(hwAttrs->baseAddr, 0,true);
object->isOpen = false;
ADCIntClear(hwAttrs->baseAddr, 0);
ADCSequenceDataGet(ADC0_BASE, 0, &Value);
}
/*
* ======== ADCTiva_init ========
*/
void ADCTiva_init(ADC_Handle handle)
{
/* Mark the object as available */
((ADCTiva_Object *) (handle->object))->isOpen = false;
}
/*
* ======== ADCTiva_open ========
*/
ADC_Handle ADCTiva_open(ADC_Handle handle, ADC_Params *params)
{
unsigned int key;
ADCTiva_Object *object = handle->object;
ADCTiva_HWAttrs const *hwAttrs = handle->hwAttrs;
union {
Semaphore_Params semParams;
Hwi_Params hwiParams;
} paramsUnion;
/* Determine if the device index was already opened */
key = Hwi_disable();
if(object->isOpen == true){
Hwi_restore(key);
Log_warning1("ADC:(%p) already in use.", hwAttrs->baseAddr);
return (NULL);
}
/* Mark the handle as being used */
object->isOpen = true;
Hwi_restore(key);
/* Create Hwi object for this I2C peripheral */
Hwi_Params_init(&(paramsUnion.hwiParams));
paramsUnion.hwiParams.arg = (UArg)handle;
paramsUnion.hwiParams.priority = hwAttrs->intPriority;
Hwi_construct(&(object->hwi), hwAttrs->intNum, ADCTiva_hwiFxn,
&(paramsUnion.hwiParams), NULL);
/*
* Create threadsafe handles for this I2C peripheral
* Semaphore to provide exclusive access to the I2C peripheral
*/
Semaphore_Params_init(&(paramsUnion.semParams));
paramsUnion.semParams.mode = Semaphore_Mode_BINARY;
Semaphore_construct(&(object->adcSem), 1, &(paramsUnion.semParams));
ADCIntClear(hwAttrs->baseAddr, 0);
ADCSequenceEnable(hwAttrs->baseAddr, 0);
ADCIntEnable(hwAttrs->baseAddr, 0);
/* Return the address of the handle */
return (handle);
}
So, using the XGCONF window, I was able to create a hwi, setting the interrupt number = 30 (as from the table in the datasheet), and associating the corresponding hwiFxn that I have written in the empty.c. file.
The function in the empty.c is the following:
int32_t read;
uint32_t Value;
Void myADCFnx(UArg arg){
ADCIntClear(ADC0_BASE, 0);
read=ADCSequenceDataGet(ADC0_BASE, 0, &Value);
}
Now, after fix some problems, I finally was able to build the project without errors or warnings.
BUT, I am not able to "generate" the interrupt. This is probably the main goal that I wanna reach.
Once the interrupt was correctly generate/recognized "It's all downhill from here"!!!
Setting a breakpoint on the above function, in debug mode, I'm sure that the function was never called.
Probably I miss something or I am setting something wrong.
Can you help me? xD
Thanks a lot
Fede