How do I configure the TWR-K24 for software triggered ADC sampling?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How do I configure the TWR-K24 for software triggered ADC sampling?

Jump to solution
685 Views
dbwolfe
Contributor III

Hi,

 

I am trying to set up the K24 for single, software triggered ADC sampling.  I have looked through the ADC example in the SDK for this board, as well as a couple other user examples, and tried to adapt them as best I could to what I want to do.  Below is some modified code from the ADC example.

 

void ADC16_Measure(void)

{

    // Software trigger the conversion.

    ADC16_DRV_ConfigConvChn(FSL_ADCONV1, ADC16_CHN_GROUP, &adConv1_ChnConfig0);

 

    // Wait for the conversion to be done.

    ADC16_DRV_WaitConvDone(FSL_ADCONV1, ADC16_CHN_GROUP);

 

    // Fetch the conversion value.

    adcValue = ADC16_DRV_GetConvValueSigned(FSL_ADCONV1, ADC16_CHN_GROUP);

 

    // Show the current temperature value.

    //printf("\r\n ADC converted value: %ld\t", adcValue );

    // Calculates adcValue in 16bit resolution

    // from 12bit resolution in order to convert to temperature.

#if (FSL_FEATURE_ADC16_MAX_RESOLUTION < 16)

    adcValue = adcValue << 4;

#endif

}

 

The actual configuration should be handled by the processor expert, so I deleted the initialization lines.  All of this code runs fine, but when some time after the method returns, the program gets stuck in the default ISR.  Here is a code snippet of my main where I call the ADC sample method, and the assembly routine starting at "read2"

 

int main(void) {

 

    /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/

    PE_low_level_init();

 

    /*** End of Processor Expert internal initialization.                    ***/

    const uint8_t gateDelay = 5;

 

    for (;;) {

        ra = gateDelay;    //Load the gate delay into r0, used in StartTiming routine

        __asm("bl StartTiming");

        //Read sample 1 from ADC here

        ADC16_Measure();

        __asm("bl read2");

 

 

 

 

read2:

    movw r3, #0x1000    // bit mask for GPIO

    str r3, [r2, #8]    // Clears GPIO

    nop                    // Delay 8ns/nop

    nop

 

Basically, I am running an assembly routine, and at several points I need to return to main from the routine to grab an ADC sample.  The program is able to run the ADC code and re-enter the assembly routine at the label "read2" using branch and link, but then a few instructions after "read2" the program gets stuck in the default ISR.  I'm reasonably sure the assembly code has nothing to do with it, since the instruction where it hangs is the first nop.

 

Here is the config screen for the PE fsl_adc16 module:

 

114191_114191.pngpastedImage_0.png

Labels (1)
0 Kudos
1 Solution
409 Views
dbwolfe
Contributor III

UPDATE: Oddly, clobbering R2 and R3 WAS causing the problem.  Changing the entry and exit code to push/pop {r1-r7 ...     from {r4-r7... fixed the bug.  In case anyone sees this and intends to use the assembly code snippets, I corrected them.

EDIT:  Thought I had the problem solved, but no, still the same bug.  Least significant 9 bits in the XPSR are, indeed, 3.   As for not using assembly,  that isn't an option due to timing requirements.  If I use assembly for GPIO, it looks like this:

ldr r2, =0x400ff0c0    // Loads the GPIOD base address into r2

  movw r3, #0x1000    // bit mask for pin PTD12

  str r3, [r2, #8]    // Clears PTD12

and then, if I want to set a different pin on port D,  all I have to do is one more move, and the same store instruction, but with a different immediate offset, only a couple clock cycles.

If I use C code, on the other hand, writing one pin turns into something like 5 or 6 lines of code, every time I want to write a pin, because the pseudocode is something like

1. load GPIO base address into reg A

2. load GPIO base address plus some offset into reg B

3. load contents of memory location stored in reg B into reg C

4. logical OR bitmask with reg C

5. store contents of reg C into memory address stored in reg A plus some offset

6. return

plus the overhead of constantly branching in and out, even for back to back writes.  Some of that *might* get optimized out by the compiler, but from my own experiments using an oscilloscope, the different between two back to back writes using C and two back to back writes with my assembly method is 180ns for C and 8, yes 8, nanoseconds for assembly.

Anyways, the entry and exit code I used, taken from an IOS programming site, are

Entry:

push {r1-r7, lr}

add r7, sp, #12

push {r8, r10, r11}

sub sp, sp, #36

Exit:

add sp, sp, #36

pop {r8, r10, r11}

pop {r1-r7, pc}

I assumed that pushing and popping the scratch registers plus the LR and R8/R10/R11 would be sufficient, but I'm still getting the error.  I can try pushing the scratch registers too (except R0, which is an argument for my routine), but my assembly routine isn't interrupting anything, and they're called scratch registers for a reason.

View solution in original post

0 Kudos
3 Replies
409 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Davin,

Regarding your question that the K24 stuck in the default ISR because of unknown reason. After the K24 enters default ISR, pls check the low 9 bits in XPSR register to know the interrupt source vector so that you can know the interrupt source. Most of time, I suppose it is 3, which means hard fault.

Regarding your code, if you use "C plus Assembly" programming, you should read the calling convention of the compiler you are using, and comply to the regulation, for example you should understand which register you can use, which register should be saved in callee function, how the parameters are transferred. For example, in the read2() function, you do not push/pop r2 and r3, it may leads to issue.

I suggest you use C language programming so that the C compiler can do all the work.

BR

Xiangjun Rong

0 Kudos
410 Views
dbwolfe
Contributor III

UPDATE: Oddly, clobbering R2 and R3 WAS causing the problem.  Changing the entry and exit code to push/pop {r1-r7 ...     from {r4-r7... fixed the bug.  In case anyone sees this and intends to use the assembly code snippets, I corrected them.

EDIT:  Thought I had the problem solved, but no, still the same bug.  Least significant 9 bits in the XPSR are, indeed, 3.   As for not using assembly,  that isn't an option due to timing requirements.  If I use assembly for GPIO, it looks like this:

ldr r2, =0x400ff0c0    // Loads the GPIOD base address into r2

  movw r3, #0x1000    // bit mask for pin PTD12

  str r3, [r2, #8]    // Clears PTD12

and then, if I want to set a different pin on port D,  all I have to do is one more move, and the same store instruction, but with a different immediate offset, only a couple clock cycles.

If I use C code, on the other hand, writing one pin turns into something like 5 or 6 lines of code, every time I want to write a pin, because the pseudocode is something like

1. load GPIO base address into reg A

2. load GPIO base address plus some offset into reg B

3. load contents of memory location stored in reg B into reg C

4. logical OR bitmask with reg C

5. store contents of reg C into memory address stored in reg A plus some offset

6. return

plus the overhead of constantly branching in and out, even for back to back writes.  Some of that *might* get optimized out by the compiler, but from my own experiments using an oscilloscope, the different between two back to back writes using C and two back to back writes with my assembly method is 180ns for C and 8, yes 8, nanoseconds for assembly.

Anyways, the entry and exit code I used, taken from an IOS programming site, are

Entry:

push {r1-r7, lr}

add r7, sp, #12

push {r8, r10, r11}

sub sp, sp, #36

Exit:

add sp, sp, #36

pop {r8, r10, r11}

pop {r1-r7, pc}

I assumed that pushing and popping the scratch registers plus the LR and R8/R10/R11 would be sufficient, but I'm still getting the error.  I can try pushing the scratch registers too (except R0, which is an argument for my routine), but my assembly routine isn't interrupting anything, and they're called scratch registers for a reason.

0 Kudos
409 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Devin,

It is difficult to track the error  without source code, I suggest you attach all the project so that we can test your code based on our board.

BR

Xiangjun Rong

0 Kudos