Frankiesayrelax 0 Posted February 28, 2015 I am using Keil uVision 5 IDE and the microcontroller is the TM4C123GH6M. At the moment, all I am trying to do is to get some analogue to digital conversion happening on a single input pin. I am using the datasheet with this tutorial on youtube as a guide, here: I understand all the steps except for using an interrupt to know when each A to D conversion has ended. I have read the Keil user guide on what interrupts are and how you can use them:http://www.keil.com/support/man/docs/c51/c51_le_interruptfuncs.htmAnd as usual, I really don't understand what it said. It gave me a general idea on what interrupts are but not on how to use them. In the past I have found Keil, both the IDE itself and the "help and support" webpage they give to be extremely user unfriendly and entirely unhelpful. Or maybe I am just terrible at programming! I also looked up the address of the interrupt in the interrupt vector address table in the datasheet and the one I want to use is for the ADC 1 Sequencer 3, the address is 0x0000.010C. It is interrupt number 51 in the register.The tutorial mentions finding a cstartup_M.c file at around 15 minute, 40 second mark, including it in the source group and modifying it, but I can't find it anywhere in any of the project folders or directories. Basically, the most important thing is I want to know how to use interrupts and if any of you have the time, I would like to know what exactly he is doing when he starts talking about interrupts at the 15.25 mark and including this source file. Thanks a lot for reading. Quote Share this post Link to post Share on other sites
mgh 11 Posted March 25, 2015 I'm not sure I can help, but I'll give it a try. First, that link was for the Intel 8051, a 8-bit microprocessor from the 1980s. Some general notions of interrupts applied, but I found it pretty confusing since none of the details concerned us. Have you loaded the TM4C "pack" for Keil's product? Just checking. There's bound to be some relevant files under there. I found some interesting pages on Keil's site. When you do a search, there's an 'advanced' search option. Using that, I searched under the ARM products only, for 'cortex interrupt' and some likely articles turned up. Here's one for the ADC on the STM32F : http://www.keil.com/support/man/docs/gsac/gsac_adc.htm Not exactly what we wanted, but it shows the things we'll have to do, since it's basically the same core with different peripherals. And maybe bookmark this, it looks very useful for using their IDE: http://www.keil.com/support/man/docs/gsac/gsac_intro.htm If you haven't already, install TI's Tivaware package - or at least unpack it; it has many examples for you under SW-EK-TM4C123GXL-2.1.0.12573/examples/boards/ek-tm4c123gxl TI has some good support videos and documents over here: http://www.ti.com/TM4C123G-Launchpad-Workshop There's a video specifically for interrupts; and see pages 4-7, 4-17, 4-18 of the TM4C123G_LaunchPad_Workshop_Workbook.pdf Again, it's not a perfect match, since it uses TI's CCS instead of Keil's uVision. Oh, well, I'm using gcc on OS X, so they're both foreign to me. An interrupt is just the hardware making a subroutine call for us, behind our backs, unexpectedly. The interrupt handler has to be careful not to trash any variables that other parts of our code might be using. And, other parts of our code might have to be careful not to assume they know the values of the data that the interrupt routine touched. I don't think you have to play with the priority register at first. Just get a plain interrupt happening; later tweak the priorities if you need to. All we do is: - set the bits in the ADC registers to allow interrupts - define a interrupt handler - put the name of the interrupt handler in the startup code I'm guessing that cstartup_M.c file was for the 8051. In the Tivawave examples, the file is startup_rvmdk.S for the Keil compiler. Just find the line that has 'ADC1 Sequence 3' and replace 'IntDefaultHander' with the name of your ADC1 sequence 3 handler. ;; startup_rvmdk.S - Startup code for use with Keil's uVision. ... DCD IntDefaultHandler ; ADC1 Sequence 3 replace with DCD ADC1Seq3handler ; ADC1 Sequence 3 After all that, here's my contribution. It measures the internal temperature sensor on ADC0 sequencer 3 at about 1KHz, and prints the temperature to the debug UART port about every two seconds. For some reason I clocked everything slowly and used delays so that we can watch it easier on a scope. I'm not sure that makes any sense now. It uses the Tivaware functions, so if you're using direct register access, it won't map directly to your needs. I hope this helps. Good luck! /* * adci.c * adc with interrupt to measure temp * $Id:$ * * NOTE! add ADC0handler to startup_gcc.c (or whatever your IDE uses) * void ADC0handler(void); // declare it * ... * ADC0handler, // ADC Sequence 3 * * LED indicators * red PF1 triggered conversion, waiting for conversion to finish * blue PF2 inside ADC interuppt handler, reading conversion data * green PF3 got conversion * * To make things take longer, to maybe see better on a scope, * both the processor and ADC run from from slower clocks, * and the ADC uses hardware averaging. * * The repetition rate of the loop is about 775Hz. * It waits about 137 usec for a conversion complete. * The ADC interrupt routine takes about 9.5 usec. * * About every two seconds the loop prints a line to UART0 * $08dc 2268 10 C 50 F * * Warm up (or cool off) your thumb, and hold against the chip, * to see the temperature change. */ #include <stdbool.h> #include <stdint.h> #include "inc/tm4c123gh6pm.h" #include "inc/hw_memmap.h" #include "driverlib/adc.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" // define the peripheral/port/pins for the LEDs #define LED_PERIF SYSCTL_PERIPH_GPIOF #define LED_PORT GPIO_PORTF_BASE #define LED_RED GPIO_PIN_1 #define LED_GREEN GPIO_PIN_3 #define LED_BLUE GPIO_PIN_2 #define LEDS (LED_RED|LED_GREEN|LED_BLUE) #define LED_SET(X) ROM_GPIOPinWrite(LED_PORT, LEDS, (X)); // this array must be big enough to hold the channels we convert // (only need one entry for this example) uint32_t rawtemp[4]; // this flag is set by the interrupt routine, and read by the wait loop volatile uint32_t newtemp; // this is the interrupt routine for the ADC void ADC0handler(void) { LED_SET(LED_BLUE); // clear the interrupt flag, grab the data, set the 'done' flag ROM_ADCIntClear(ADC0_BASE, 3); ROM_ADCSequenceDataGet(ADC0_BASE, 3, rawtemp); newtemp = 1; LED_SET(0); } void InitADC(void) { // enable ADC0 // set a slower conversion rate // use sequencer 3 (single sample), with manual trigger // seq 3, step 0, temperature-sensor, interrupt-enable, last-conversion // enable sequencer 3 ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); ROM_SysCtlDelay(2); ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_RATE_EIGHTH | ADC_CLOCK_SRC_PIOSC, 1); ROM_ADCHardwareOversampleConfigure(ADC0_BASE, 16); // 64 32 16 8 4 2 ROM_ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0); ROM_ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END); ROM_ADCSequenceEnable(ADC0_BASE, 3); // make sure interrupt flag is clear // enable the interrupt for the module and for the sequence ROM_ADCIntClear(ADC0_BASE, 3); ROM_IntEnable(INT_ADC0SS3); ROM_ADCIntEnable(ADC0_BASE, 3); } void InitConsole(void) { // enable the port that has UART0 pins // configure the RX/TX port pins // enable the uart, set the clock, set the pins // set baud-rate ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); ROM_SysCtlDelay(2); ROM_GPIOPinConfigure(GPIO_PA0_U0RX); ROM_GPIOPinConfigure(GPIO_PA1_U0TX); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTStdioConfig(0, 115200, 16000000); } int main(void) { uint32_t i, tempC, tempF; // clock at 8 MHz from the crystal ROM_SysCtlClockSet(SYSCTL_SYSDIV_2 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); ROM_SysCtlPeripheralEnable(LED_PERIF); ROM_SysCtlDelay(2); ROM_GPIOPinTypeGPIOOutput(LED_PORT, LEDS); LED_SET(0); InitConsole(); InitADC(); UARTprintf("\n\nADC internal temperature sensor\n"); // allow interrupts ROM_IntMasterEnable(); i = 0; while ( 1 ) { // clear the flag, show we're waiting newtemp = 0; LED_SET(LED_RED); // start a conversion ROM_ADCProcessorTrigger(ADC0_BASE, 3); // spin and wait for the interrupt handler to get the data while ( newtemp == 0 ) { __asm ("WFE\n "); } LED_SET(LED_GREEN); // print temps about every two seconds if ( ++i == 2000 ) { i = 0; tempC = (1475 - ((2475 * rawtemp[0])) / 4096)/10; tempF = ((tempC * 9) + 160) / 5; UARTprintf("$%04x %4d %3d C %3d F\n", rawtemp[0], rawtemp[0], tempC, tempF); } // delay to slow down the loop to something around 1KHz ROM_SysCtlDelay(ROM_SysCtlClockGet()*3/8000); } } Quote Share this post Link to post Share on other sites
krishnat 0 Posted February 6, 2017 Hi ,which systemclock should I configure with ADC & timer module ( I am using both module in same code)..??SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 80MHzSysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 50MHzSysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 40MHzIf I dont write any of above, I get :: freq = SysCtlClockGet(); // 16MHzMy requirement is lowest execution time.Should I configure to 80MHz..?? If I do so will both ADC and Timers will work fine..??Is any extra configuration needed...?Regards,Krishnat Quote Share this post Link to post Share on other sites