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.

EK-TM4C1294XL: ADC Reg32 reserved space

Guru 56143 points
Part Number: EK-TM4C1294XL
Other Parts Discussed in Thread: INA240

How is it possible for C+ language to read reserved register bits 31:16 into a int32_t variable array yet only the lower bits 11:0 are marked as R0 in REG17,18,19,20? Why would Tivaware attempt to read reserved register bits in FIFO registers? Better yet is the Thumb instruction set somehow not allowing register reads in reserved space? If so how might uint32_t variable transfer effect the complied application attempting to crash in on the upper 31:16 bits of REG17,18,19,20 when they were not invited to the party? Is the FIFO read a 1:1 triggered level event into any C+ array variable cell, it would seem not always the case in any sequencers above 0.

HWREG 32 macro reads into these registers via proper uint16_t variable array are not returning FIFO step 0 results data from all sequencer 1 or 2 configured steps. Typically only step 1 or 2 when being read into an uint16_t array is not the intended data via typical interrupt handling of the FIFO. It would seem the ability to properly read any single step of a circular FIFO as datasheet marginalizes has left out many details of when exactly the Head or Tail pointers change after sampling has occurred. Everyone simply assumes the tail pointer is returned to step zero upon END IE of the last step sampled. Yet the datasheet leaves all such required details to making suppositions, most of which are incorrect or not producing consistent results in all sequencers. Tivaware crude ADCSequenceDataGet() attempts to push the envelope for producing useless function calls. Please write the FIFO read data function for proper business use that it may pass any single step variable to retrieve any single data step in the sequencer into an C+ uint_16 array without retuning all FIFO steps data. If it can not do that simple step on all sequencers there is an issue with the M4 ADC that the M3 did not have. 

Tivaware example projects using while(1) wait loop interrupt handling is not a safe nor practical way to handle NVIC interrupts to retrieve FIFO data in any robust application. Please use proper NVIC handling of interrupts in future example software typical of the method used in business applications of any MCU. No body is going to use while(1) loops in an large application waiting for an interrupt to occur from a triggered ADC sampling, from GPTM, PWM0, PWM1, GPIO or any other trigger source possible. That alone makes the while(1) loop more of a lower programming form thus wasting valuable CPU time and teaching bad programming methods! Again while(1) loops is not a good way for TI engineers to confirm there are not underlying issues with the ADC modules. Perhaps TI is aware odd behavior exists M4 ADC sequencers and are attempting to change the narrative of typical and proper ADC peripheral use attempting to cover them up via ADCSequnceDataGet()?

The ADC trigger is supposed to activate sampling conversion which it does for sequencer 0 steps in orderly manner but seems to often skip step 0 or 1 in SS1 or SS2 (ADC0/1), not sure about SS3. Tivaware omitting any ability to retrieve a specific sequencer step seems a bit deceptive. Underlying behavior also exists in ADC0 sequencers, ADC1 controls 19:16 channels causing issues between ADC0 & ADC1 sharing control seemingly being missed in Tivaware control over analog MUX in not 1 but 2 ADC modules. It would seem much needed information was omitted relative to how ADC0 and ADC1 can retrieve specific FIFO data of any channel as the M3 could easily accomplish via a single ADC. There are problems in the ADC modules configuration not being disclosed in the errata document. 

  • Why do you want to read the reserved field? Sorry, if that is not your question. As far as why the ADCSequenceDataGet specified a 32bit pointer for the buffer I don't know for sure as I don't have the history of the TivaWare and the ADC spec. I can image at one point of time the ADC module may have envisioned providing two ways to read the FIFO. One is the method that is currently supported - which is to read in a FIFO manner from say ADCSSFIFO0 register at 0x48. Another way is to allow CPU issue LDMIA to read up to 8 conversion results. If you look at the offset address of REG17, 18, 19 and 20 they are at 0x48, 0x68, 0x88 and 0xA8 and each FIFO address is separated by 8 words. Perhaps at one point of time each Sequencer supports 8 steps. CPU could have issue LDMIA from starting address 0x48 to read 8 conversion results in a burst operation which would have been faster. The reason I rationalize this possible scheme is because this is what we implemented in the Hercules ADC module. In any case, the way it is today is just wasting some unused space in the buffer, but the reserved space should be just ignored by the application.

    int32_t
    ADCSequenceDataGet(uint32_t ui32Base, uint32_t ui32SequenceNum,
                       uint32_t *pui32Buffer)
    {
        uint32_t ui32Count;
    
        //
        // Check the arguments.
        //
        ASSERT((ui32Base == ADC0_BASE) || (ui32Base == ADC1_BASE));
        ASSERT(ui32SequenceNum < 4);
    
        //
        // Get the offset of the sequence to be read.
        //
        ui32Base += ADC_SEQ + (ADC_SEQ_STEP * ui32SequenceNum);
    
        //
        // Read samples from the FIFO until it is empty.
        //
        ui32Count = 0;
        while(!(HWREG(ui32Base + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) &&
              (ui32Count < 8))
        {
            //
            // Read the FIFO and copy it to the destination.
            //
            *pui32Buffer++ = HWREG(ui32Base + ADC_SSFIFO);
    
            //
            // Increment the count of samples read.
            //
            ui32Count++;
        }
    
        //
        // Return the number of samples read.
        //
        return(ui32Count);
    }

  • Hi Charles,

    Charles Tsai said:
    In any case, the way it is today is just wasting some unused space in the buffer, but the reserved space should be just ignored by the application

    The problem if you noticed ADCSequenceDataGet() uses uint32_t DECL variable array to read 12 bit FIFO data into, 31:15 bits left open for mayhem? Does not that ui32_t specifically access the reserved memory space of each FIFO as it is being read?

    Even by using HWREGH (uint16_t) array to retrieve any single step into an indexed array cell somehow changes step 0 Rs impedance thus increasing the open loop gain 100x, that step only. That may also be an attribute of ADCSequenceDataGet() but unknow to anyone not using the call to retrieve FIFO data.

    The bigger problem is ADC1 overlaps 19:16 FIFO data from SS1 relative to ADC0 3:0 AIN inputs when ADCCLK changed form 32Mhz to 16Mhz Rs impedance of ADC0 step 0 increases and  ACDC1 SS1 step 0 1 decreases, FIFO data ADC1 can inflict ADC0 step 0 FIFO data. KISS test confirms the ADCCLK speed has an effect on which ADC modules sequencer step 0 open loop gain becomes impacted from the other modules FIFO data.

    In our case ADC1 SS1 was assigned AIN channels (any of 19:16), ADCCLK 2MSPS, this made ADC0 SS1 step 0 AIN (any of 3:0) inputs Rs impedance highly sensitive over other steps of sequencer. That is a real problem for three INA240 AINx inputs rely open loop SAR channel gain (Rs impedance). 

    ADC0 SS1 step 0 was current phase A and can easily false current faults in the 100x gain of step 0 if software did not subtract the excessive gain, lowering other 2 AIN inputs FIFO values. That same gain occurs in SS1 step 0 of EK/EVM via KISS test jumpers, 10k to ground on the any of (3:0) channels. The lower Rs channel impedance SS1 step 0 moves from ADC0 to ADC1 SS1 step 0 (ADCCLK speed) and FIFO (step 0) data of that ADC1 sequencer can over lap ADC0 SS1 step 0 internally though the analog mux. Even though ADC0 SS1 step 0 Rs impedance increased it received overlapping FIFO data from ADC1 SS1 step 0. Change ADCCLK 32Mhz and ADC0 FIFO step 0 Rs impedance lowers becoming highly sensitive over any other steps in same sequencer no matter the ANIx assignment from 15:0. Yet steps 1,2 AINx channels Rs impedance remains very high during sampling intervals.   

    The most important aspect AINx Rs impedance of all ADC0/1 SS1 configured steps must be fairly equal during AINx sampling. Step 0 having Rs very low impedance (100x gain) over other AINx channels in the same sequencer will never work.

    A partial WA, is to disable sequencer step 0. That begs questions, why Rs (sampling) impedance moves between ADC0/1 in sequencer step 0  and how does it effect HWREGH reads of circular FIFO data? Why does ADCCLK rate effect Rs impedance dramatically over other steps in step 0 (ADC0/1) of SS1?

  • BP101 said:
    The problem if you noticed ADCSequenceDataGet() uses uint32_t DECL variable array to read 12 bit FIFO data into, 31:15 bits left open for mayhem? Does not that ui32_t specifically access the reserved memory space of each FIFO as it is being read?

    No, your understanding is not correct. The FIFO is only 12 bits wide 'physically'. The FIFO is only 'memory mapped' to a 32-bit space. This does not mean the FIFO is implemented as a 32-bit memory. Physically in design the 12 bits FIFO data output are routed to the 11:0 of the CPU memory AHB bus while the rest of the bits 31:12 are forced zero when reading the ADCSSFIFOx registers.

  • Charles Tsai said:
    Why do you want to read the reserved field? Sorry, if that is not your question.

    Your right that was not the intent of question.

    Rather why is ADCSequenceGet() also invading reserved bit space and not somehow effecting (11:0) bits in lower (15:0) was more the point. Above I stated testing HWREGH (uint_16t) made no difference in Rs impedance of step 0 FIFO data via AIN hardware. Yet even HWREGH invades 15:12 of lower WORD may somehow inflict mayhem upon the CPU directives on the assembler level to properly read the (11:0) 12 bits of hardware FIFO data areas. 

    Perhaps more of a question how ARM Cortex handles REG reserved bits via CPU R/W instructions and what might occur to hardware during any such a violation! Old school method would have masked the lower 12bits 0xFFF yet [ HWREG(ADC1_BASE + ADC_O_SSFIFO1) &0x0FFF ] does not correct step 0 Rs impedance being lower than any other sequencer steps.

    Point is it may take special handling of the FIFO via C+ to not disturb step 0 Rs impedance during FIFO hardware reads into software C+ array cells. If your not looking or checking HW for this specific issue your not going to even know it can exist!

  • I do not see any relationship between 31:12 on the bus and the Rs impedance. Sorry, I really don't understand why are you trying to relate something that does not exist - the bits 31:12 which should always read 0 and you application should always mask them out - to have any effect on the the accuracy of the data conversion or the Rs value. A while back I posted this diagram. The conversion is done by the A-to-D Converter. The FIFO is nothing but a storage of the converted results. The FIFO plays no part on how the ADC will sample its analog inputs. There is nothing I can do if you just don't want to believe it. 

  • Charles Tsai said:
    The FIFO plays no part on how the ADC will sample its analog inputs.

    That may be an incorrect conclusion as the FIFO timing is relative to the converters sampling frame time.

    Software is currently masking FIFO every possible way (11:0) bits does not control how AD converter behaves on the silicon level relative to ADCCLK speed. Capture below indicates what some choose to believe truth isn't the full truth.

    EKXL/EVM: ADC1 SS1 step 0 CH0, step 2 CH9   each connected to 3v3 via 100k resistors. The LM94002 temperature formulas read  FIFO1 data and present it to display. When I pull 3v3 from AIN CH9  the other step data is being changed in the interrupt handlers reading of the FIFO1 into 2 array variables of specific names, LowTemp[0]  HighTemp[0]. CH0 3v3 remains connected but the value changes in CH0 (previosly CH16). Test below 1MSPS no hardware averaging 480MHz PLL. 

    Bump up the ADCCLK to 32MHz and the low impedance of CH0 then moves to ADC0 step 0 CH5, That means the AIN low Rs impedance acts like an antenna very sensitive where other steps of sequencer are not. This is direct evidence the AD converter relative to FIFO access timing has something to do with conversions in step 0. Again AINx step 0 becomes super sensitive over that other AINx in the same sequencer, how can that be? Simply put the channel acts more like an antenna, not so much a sample source governed by Rs impedance. Question is why is this happening and can it be corrected via software configuration of ADC sequencers and steps?

    // Configure ADC0 and ADC1 analog block sample clock rate
    // 32Mhz 2-MSPS Return sequencer samples FULL.
    // 2MSPS: SYS clock PLL480/15=32MHz 31.25ns.
    // 1MSPS: SYS clock PLL480/30=16MHz 59.6ns.
    // ADC module can use alternate clock source PIOS set via ADCALTCK
    
       ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);
    
        /* Configure both ADC0/1 VREFP = external +VRefA[1] or VDDA[0] 3v3 */
    	MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);//ADC_REF_EXT_3V, ADC_REF_INT
    	MAP_ADCReferenceSet(ADC1_BASE, ADC_REF_INT);//ADC_REF_EXT_3V, ADC_REF_INT

    HWREG(ADC1_BASE + ADC_O_SSTSH1) = 0x2222;
    
    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 0, PIN_MOSTEMP_LOW1);  //AIN0 was AIN16
    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 1, PIN_MOSTEMP_HIGH1 | ADC_CTL_IE); //AIN9
    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_END);

    hw_types.h
    
    #define HWREGI(x)                                                             \
            (*((volatile int16_t *)(x)))
    
    *****************************************************************************/
    void
    ADC1MOSTempHandler(void)
    {
    
        volatile int16_t int16Temp;
        int16_t int16ADC1MOSTempLow[1];
        static int16_t int16TempLow;
        int16_t int16ADC1MOSTempHigh[1];
        static int16_t int16TempHigh
    
    
         /* Clear ADC1 SS1 interrupt */
         MAP_ADCIntClear(ADC1_BASE, 1);
    
    
         /* Disable the SS1 sequence.*/
         HWREG(ADC1_BASE + ADC_O_ACTSS) &= ~(ADC_ACTSS_ASEN1);
    
    	 /* Read sensitive RAW sample sequence steps ADC1 FIFO-1. */
    	  int16ADC1MOSTempLow[0] = HWREGI(ADC1_BASE + ADC_O_SSFIFO1) & 0x0FFF; 
    	  int16ADC1MOSTempHigh[0] = HWREGI(ADC1_BASE + ADC_O_SSFIFO1) & 0x0FFF;
    	  /* Dummy read for FIFO step 2 END */
    	  //int16Temp = HWREG(ADC1_BASE + ADC_O_SSFIFO1);
    
    
    	  /* Drain the SS1 FIFO 1. */
    	  while(!(HWREG(ADC1_BASE + ADC_O_SSFSTAT1) & ADC_SSFSTAT1_EMPTY))
    	  {
    	    /* Empty the circular FIFO. */
    	     int16Temp = HWREGI(ADC1_BASE + ADC_O_SSFIFO1);
    	  }
    	  /* Clear (RW1C) the FIFO SS1 Overflow and Underflow status bits.*/
    	   (HWREGBITW(ADC1_BASE, ADC_O_OSTAT) |= ADC_OSTAT_OV1);
    	   (HWREGBITW(ADC1_BASE, ADC_O_USTAT) |= ADC_USTAT_UV1);
    
    	  /* Re-enable SS1 sequence and return.*/
    	   HWREG(ADC1_BASE + ADC_O_ACTSS) |= ADC_ACTSS_ASEN1;
    
    		 /* Check ADC1 SS1 FIFO (RW1C) Overflow or (RW1C) Underflow status. Or if
    		  * FIFO-1 is FULL (RO) after reading what should have been all of the data.*/
    		  if((HWREG(ADC1_BASE + ADC_O_OSTAT) & ADC_OSTAT_OV1) ||
    			  (HWREG(ADC1_BASE + ADC_O_USTAT) & ADC_USTAT_UV1) ||
    				(HWREG(ADC1_BASE + ADC_O_SSFSTAT1) & ADC_SSFSTAT1_FULL))
    			 {
    				/* Disable the SS1 sequence.*/
    				  HWREG(ADC1_BASE + ADC_O_ACTSS) &= ~(ADC_ACTSS_ASEN1);
    
    				/* Drain the SS1 FIFO 1. */
    				while(!(HWREG(ADC1_BASE + ADC_O_SSFSTAT1) & ADC_SSFSTAT1_EMPTY))
    				{
    					 /* Empty the circular FIFO. */
    					 int16Temp = HWREGI(ADC1_BASE + ADC_O_SSFIFO1);
    				}
    				 /* Zero the Analog temperature variables */
    				   int16ADC1MOSTempLow[0] = 0;
    				   int16ADC1MOSTempHigh[0] = 0;
    
    				/* Clear (RW1C) the FIFO SS1 Overflow and Underflow status bits.*/
    				  (HWREGBITW(ADC1_BASE, ADC_O_OSTAT) |= ADC_OSTAT_OV1);
    				  (HWREGBITW(ADC1_BASE, ADC_O_USTAT) |= ADC_USTAT_UV1);
    
    				 /* Renable SS1 sequence and return.*/
    				  HWREG(ADC1_BASE + ADC_O_ACTSS) |= ADC_ACTSS_ASEN1;
    
    				  return;
    		     }
    
    		   /* Filter ADC1 sequencer 1 analog input PIN_MOSTEMP_LOW1, PIN_MOSTEMP_HIGH1 by
    			* 
    			* couple to output each LM94002Q PCB mounted temperature sensors.
    			* Temperature to analog voltage range GS0/1=11, tables in datasheet */
    
    		    int16TempLow = (((int16TempLow * 7) + int16ADC1MOSTempLow[0]) / 8);
    		    int32MOSTempValueLow  = (((1884 * 4096) - (2284 * int16TempLow)) / 4870);
    
                int16TempHigh = (((int16TempHigh * 7) + int16ADC1MOSTempHigh[0]) / 8);
                int32MOSTempValueHigh = (((1884 * 4096) - (2284 * int16TempHigh)) / 4870);
     /* Print the current temperatures of MOSFET Q1 and Q5 */
     UARTprintf(">> MOSTempLow -->:%i*C\n", int16ADC1MOSTempLow[0]);
     UARTprintf(">> MOSTempHigh-->:%i*C\n\n", int16ADC1MOSTempHigh[0]);

  • I don't understand the formula shown below as to 1884, 2284 and 4870 and all the multiply and divide. Why don't you print the raw FIFO value onto the display and show exactly what you get vs what you expect to read before the AIN9 is connected to 3.3V vs. removed.
    int16TempLow = (((int16TempLow * 7) + int16ADC1MOSTempLow[0]) / 8);
    int32MOSTempValueLow = (((1884 * 4096) - (2284 * int16TempLow)) / 4870);

  • Charles Tsai said:
    Why don't you print the raw FIFO value onto the display and show exactly what you get vs what you expect to read before the AIN9 is connected to 3.3V vs. removed.

    Oddly when step 1 AIN9 (MOSTempLow) is taken to ground, step 0 AIN0 remains fairly close to -28.5*C (+3.295v) , decimal point assumed. Yet when step 0 AIN0 taken to ground both values change to positive integers. When both AIN0, AIN9 are taken to ground both Low and High are exact same value (158.4*C) so the formula scale is fairly linear to datasheet tables.  

    Admittedly impedance moving issue noted in ADCCLK frequency changes was partially my bad. Modified ADC0 SS0 code with cut paste dummy FIFO step load from ADC1 SS1 code and a later CTRL-Z switched it back after it was edited. Checked that same code many times late yesterday didn't see any connection to ADC1 but there it was big as life.

    Still does not explain how (MOSTempLow) ADC1 SS1 AIN16 in custom PCB is being plagued by ADC0 SS1 even after checking for CTRL-Z ditto mistakes, there are none to be found. Hope the HWREGI (int16_t) macro will help in that sequencer too since it did not exist in Tivaware prior to today.  

  • Charles Tsai said:
    I don't understand the formula shown below as to 1884, 2284 and 4870 and all the multiply and divide

    Try it out on a ADC sequencer, formula is low pass noise filter coupled to the LM94002 temperature scale -50*C (+3.25v) up to 150*C (538mV) or ground for the sake of simplicity. The LM94002 transfer table don't show tenths of a degree C volts but the formula is more accurate than Transfer table 1, down to 10mV per degree C seems very close to precision.

  • Even after changing CH9 to CH16 results still do not rectify how VREFP (3V3) seems 1/2 what it should be for AIN=3v3.

    The UARTprintf() is located on right side of FIFO read data and USBprintf() left side printed results. Results seems to indicate step 0 relative to step 1 somehow enters AINx differential mode or is already in differential mode when the channel voltage polarity is swapped between the two channels.

  • Charles Tsai said:
    No, your understanding is not correct. The FIFO is only 12 bits wide 'physically'. The FIFO is only 'memory mapped' to a 32-bit space.

    I would have to believe a peripheral register is considered physical data I/O address space. Memory mapped address often relates SRAM, Flash, EEROM being involved. Yet Bob believed FIFO 12 bits are merely shift registers, thus reserved space relates more to physical address space not memory mapped address space.  I would not get the impression 31:12 are being forced to any value when being reserved space, it should not be accessible by CPU instructions or cause odd behavior attempting to read 32 bits into 16bit CPU accumulator. Seem to recall Intel 486 CPU's were once designed with 16 bit registers and 32 bit CPU core, bottle necking occurred but it was fast for the time.

    That said the datasheet does not show the AHB/HB being 32bits wide (bus matrix) but states the ARM cortex M4F 32 bit (core) and begs question the AHB even being 32 bits wide, more likely 16 bits wide bus matrix.

    ■ Thumb-2 mixed 16-/32-bit instruction set delivers the high performance expected of a 32-bit ARM core in a compact memory size usually associated with 8- and 16-bit devices, typically in the range of a few kilobytes of memory for microcontroller-class applications