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.

RTI COMP0 not triggering ADC2EV

Other Parts Discussed in Thread: HALCOGEN

Hi,


I seem to be having problems with setting the RTI to trigger the "Event Group" of mibADC2.  Please find attached the code I've written, originally I had it setup to trigger the "Event Group" of mibADC1, but I found I had to swap ADC1 and ADC2 around as I was unable to use ADEVT2 but ADEVT1 is available in my design as the trigger for mibADC1 via DMA.


On the TMS570LS313xHDK, the RTI is triggered (confirmed via notification) however the mibADC2 does not start/complete. Any suggestions?

Cheers,

Alan 

  • Hi Alan,

    I don't see an attachment.

    There are 2 sets of trigger maps for the ADCs - a default one and an alternate one.  There's some bits I think in the IOMM that select one map versus the other.  IMO the alternate is more interesting but the default is there for backward compatibility w. previous devices.   So I'm wondering if you're doing something simple like using the alternate table but are setup for the default table.

     EDIT:  Actually RTI Comp 0 happens to be # 4 in both the normal and the alternate map so it wouldn't matter which one you picked.  And they're also #4 for the MibADC1 and MibADC2 so it's hard to understand why the same setup would not work just because you swapped ADCs. 

    Where do the ADEVT pins come in ?  Were they just a resource conflict forcing you to swap which ADC was being used for the RTI trigger ... or they involved in the RTI trigger that you're trying to setup (they should not be involved in the RTI trigger....)

     

  • Here is the attachment 7725.HDK_DMA_ADC.zip


    Sorry I confused things there, without the code my comments about ADEVT1/2 did not make much sense, I was just trying to give background to my code.


    To single out the problem it is just with the RTI_COMP0 not triggering mibADC2.

    Alan

  • Alan,

    I did this:

    • Commented out line 96 of sys_main.c [dmaEnable()]
    • Commented out line 99 of sys_main.c [setupDMA()]
    • Set breakpoint at return statement of rtiNotification in file notification.c (line 73)
    • Ran code from a reset (CPU & System) to the breakpoint in the rtiNotification

    And by inspecting the ADC2 module, I can see that the ADC2 was triggered.   The reason I took out the dma was just to keep the ADC flags from being cleared by the DMA so that we could see for sure if it was triggered or not triggered.

    Screenshot below - see how the EvIntFlg register reads 0x9 (event group complete and fifo threshold) instead of the initial value of 0x4 (memory empty)...

    So, I think the problem you're having is probably further downstream.   It appears that you've got the DMA moving the data directly from the ADC to the DCAN.

    Suggestions for next steps would be:

    1. reproduce what I tried on your own setup to verify you get the same results
    2. if so, then I would suggest changing the DMA configuration so that you transfer from the ADC to RAM;  but *only* change this.   Then you can inspect the RAM to see if the transfer occurred and if it followed the pattern that you thought it would be following.

    I'm guessing that the DMA is actually working too;  and suspect the issue might be in the ADC -> DCAN path.

    I skimmed your DMA config, but didn't really grasp what it was trying to do.  Especially since one DMA seemed to be setup to read from ADC and write back to the ADC RAM (?) 

    Maybe you can let me know the type of DMA transfer that you're trying to setup, and whether you are trying to send data from both MibADC1 and MibADC2 out the same DCAN port and through the same DCAN IF[x] register set?  If that's what you're attempting to do then the problem is likely in the DMA setup.  The IF[x] interfaces can't really be shared that way.    Also, even if you're using different IF[x] register sets, you would need to be writing to two different mailboxes or again the data from one converter would overwrite the other.

  • Hi Anthony,

    Thanks for having a look at my code, I tried your recommendations and can confirm ADC2 Event Group is being triggered.  I've since tidied up my code and edited it so that the comments match the code. 7674.HDK_DMA_ADC.zip

    To explain:

    -RTI triggers ADC2 Event Group

    -Completion of ADC2 Event Group triggers DMA_CH0 which moves 7 x uint32 from adcREG2->GxBUF to canREG1->IF1DATx

    -Completion of DMA_CH0 triggers DMA_CH1 which transfers the values needed to send the data via message box 52 to CAN2 (CAN1 and 2 are joined via external connection)

    -Completions of DMA_CH1 triggers DMA_CH2 which places 1U into adcREG1->EVTOUT to start ADC1 Event Group

    -Once ADC1 Event Group is completed DMA_CH3 is triggered which moves 7 x uint32 from adcREG1->GxBUF to canREG1->IF1DATx

    -Completion of DMA_CH3 triggers DMA_CH4 which transfers the values needed to send the data via message box 59 to CAN2 (CAN1 and 2 are joined via external connection)

    -Completions of DMA_CH4 triggers DMA_CH5 which places 0U into adcREG1->EVTOUT to prepare the trigger for the next loop.

    Is there a way of monitoring what the DMA is doing in terms of where it is copying ISADDR, IDADDR, CHCTRL and the rest of the info stored in the g_dmaCTRL array to make sure the right data is being provided to the DMA?

    In the final design the period of RTI_COMPARE0 will be ~1 minute, even with the use of different message boxes do you see this as a problem? Unfortunately the design of the board is finalised and I do not have access to DCAN2.

    Cheers,

    Alan

  • Hi Alan,

    I didn't look at your new code yet, but I've got some questions about the description above:

    Just a couple of quick questions:

    Alan Day said:
    -Completion of ADC2 Event Group triggers DMA_CH0 which moves 7 x uint32 from adcREG2->GxBUF to canREG1->IF1DATx

    I think I remember you had the ADC setup for 8 bit data mode, so really the DMA is moving 8 x uint8 from ADC to the  canREG1->IFDATx[] register set, is that right ?    It might be reading with an access size of uint32 from the ADC but it can only write the lower 8 bits of this to the CAN because the IFDAT[x] registers are just 8 bytes of payload.   Just want to confirm this is what you're trying for.

    Alan Day said:
    -Completion of DMA_CH0 triggers DMA_CH1 which transfers the values needed to send the data via message box 52 to CAN2 (CAN1 and 2 are joined via external connection)

    I think I read this bullet too quickly the first time and was confused, but I'll ask anyway.  DMA_CH1 is transferring the values to sent data via message box 52 of CAN1 (finishing the write to IF1[]) and you have CAN2 setup to receive this message as a sort of monitor.  Is that correct?

    Alan Day said:
    -Completions of DMA_CH1 triggers DMA_CH2 which places 1U into adcREG1->EVTOUT to start ADC1 Event Group

    -Once ADC1 Event Group is completed DMA_CH3 is triggered which moves 7 x uint32 from adcREG1->GxBUF to canREG1->IF1DATx

    -Completion of DMA_CH3 triggers DMA_CH4 which transfers the values needed to send the data via message box 59 to CAN2 (CAN1 and 2 are joined via external connection)

    -Completions of DMA_CH4 triggers DMA_CH5 which places 0U into adcREG1->EVTOUT to prepare the trigger for the next loop.

    OK I think the pieces are coming together regarding the ADEVT question I had.   So bascially you are not triggering the two ADCs together off the RTI COMP0;  you're only triggering ADC2.  This kicks off a chain of DMA transfers and then as part of this group of transfers you're toggling ADEVT to start ADC1 after the ADC2 conversion has completed and data is moved to DCAN.   If we had a different RTI COMP available for triggering ADC1 it might have been a lot easier to control the delay between ADC2 and ADC1 starting;  but we dont and the ADEVT pin is the next best option.   Is that right?

    Alan Day said:
    Is there a way of monitoring what the DMA is doing in terms of where it is copying ISADDR, IDADDR, CHCTRL and the rest of the info stored in the g_dmaCTRL array to make sure the right data is being provided to the DMA?

    You can read the primary control packets after they have been copied to the ADC RAM and before the ADC channel starts converting to make sure they are written correctly.

    Once the DMA channel begins transferring data, inspecting the working value of the pointers (ie. source address, dest, and count) is tricky because they are not written back to the Working Control Packet area of the DMA RAM unless they have to be.  That means for the Working Control Packet area to have meaningful data you need to have another channel 'interrupt' the transfer of the first channel to force the DMA controller to do the write-back.
    In other words, the 'Working Control Packet' can be thought of as a scratchpad for the DMA but not necessarily a tool for the human debugging the DMA.

    The DMA does have a watchpoint feature that you can use to break the CPU once the DMA channel reads or writes to a certain address.   So if you have questions about whether or not a certain write occurs, you can use the watchpoint to verify that the read or write occurs.

    Alan Day said:
    In the final design the period of RTI_COMPARE0 will be ~1 minute, even with the use of different message boxes do you see this as a problem? Unfortunately the design of the board is finalised and I do not have access to DCAN2.

      

    I'd say this depends.   It would be rather extreme but I suppose there's no guarantee that in 1 minute the CAN message is actually transferred so you might overwrite the message with the next message and this would manifest as a missing message.  The DCAN IF register set does ensure the integrity of the message, you won't get 1/2 the payload from the second message and the other half from the 1st message.

    So if you can tolerate this case then I think it's ok.    You are using different mailboxes for the ADC1 and ADC2 data so your time for conflict on the mailbox is your ~1 minute  and it's same ADC conflicting w. same ADC...

    It's a little 'unsafe' to not check the IF register set for busy before writing to it.  But the time to copy from the DCAN IF register set into the mailbox RAM is bounded and I think we could probably confirm that it's less than the time for the ADC although this is probably worth verifying.  

    I think it makes sense to check the DCAN spec to see what happens if you're writing to IF[x] to copy into message box 52 when the CAN is actively transferring the previous data from box 52.  If it holds off IF[x] (delays it) then maybe the time to finish that message could be long enough to cause a conflict at the IF[x] register set.

    But I doubt you're seeing any issue here today if you're just doing a loopback test.   More of something to come back and confirm.

    The potentially bigger question I have is what are the CAN interrupt drivers doing to read/write the CAN RAM.

    The IF1, IF2 and IF3 register sets are basically 'global' resources, and I think the clean way to make it work is something like writing to the mailboxes would use IF1 and be done by one task/function,   reading would be done through IF2, and DMA's would go through IF3.   Something like that.

    Because if the CPU and the DMA both go for the same IF[] register set simultaneously, there would be a problem.

    By the way - is the code that you attached above working now, or is there still a problem to debug?

  • Hi Anthony,

    Unfortunately it does not look like the DMA is doing what I intend.  Here are the answers to your questions:

    1 - Yes sorry you are correct I've set the DMA read/write only 8bits

    2 - Yes I've set up DCAN2 so that I can ensure the data is being transferred to DCAN1 and sent correctly

    3 - Yes given the options ADEVT1 offers the most controlled way of doing this and hopefully avoiding lost messages/data.

    4 - Can you explain this DAM watchpoint? do you mean the use of dmaEnableInterrupt?

    5- Thanks for the input here, I will check this once I have it all working, I will also need to check it under the worst case scenario with multiple agents on the CAN bus. 

    Can you explain how the DMA would go through IF3, I though I read in the TRM that this is only for reading.

    In the final code any other use of CAN will first stop the RTI, check the ADC is not in the process of a conversion then finally check if a message is pending so there should not be any DMA/CPU conflict.

    cheers,

    Alan

  • Hi Alan,

    Alan Day said:
    4 - Can you explain this DAM watchpoint? do you mean the use of dmaEnableInterrupt?

    If you haven't already, you might want to explore the Breakpoints window in a CCS session.
    Normally you might just double click on some address in the source and a breakpoint will automatically be set, but through the breakpoints window there are more options - hardware watchpoint is one of them.   The hardware watchpoint lets you break the CPU whenever the CPU performs a *memory access* to a certain address, and you can filter further by type of access.    So let's say you've got some variable in RAM that's getting corrupted but you have no idea how or by what code, you can set a watchpoint to halt the CPU whenever it writes to the particular address in RAM (or range of addresses) and use this to figure out which code is causing the problem.

    The DMA has similar capability, but there's no GUI support for it in CCS;  you just program the watchpoint control registers.  These are WPR and WMR - you can find them in the TRM in the list of DMA registers.  There's also DCTRL that enables the watchpoint and when you break it tells you which DMA channel mad the access.  It's pretty simple.  You program the address you want to watch in the WPR,  and there is a mask register to mask off address bits which gives you 'range' capability.  When you hit a DMA watchpoint, you'll stop in your code just like a regular watchpoint.  Your code window won't show anything (like you might be used to when you halt at a breakpoint and you see your code window on a line that's got the breakpoint symbol) but you can read the DMA's DCTRL register to confirm that the DMA stopped you.

    There is one 'quirk' to all this.  You can't disable the watchpoint once you enable it except by a power on reset.   That's just a nusiance though because you can program the watchpoint to some address you know isn't valid and you won't access and this is almost as good as disabling it.  (and if you actually do halt on this condition - it's probably good to know!)

    Alan Day said:
    Can you explain how the DMA would go through IF3, I though I read in the TRM that this is only for reading.

    My mistake.  You're right.  I had it in my head that IF3 = DMA which is wrong.

    Alan Day said:
    In the final code any other use of CAN will first stop the RTI, check the ADC is not in the process of a conversion then finally check if a message is pending so there should not be any DMA/CPU conflict.

      Ok. I guess managing the IF[x] register set is a sort of art form.  That seems like one way to handle the problem.  Just curious then, how do you use IF1 and IF2?  The reason I was thinking use one for reads and another for writes was to minimize the changes needed to the control part or the IF register and mainly write to the data bytes.  But you could probably also partition them between any two masters or tasks.    Also wondering if it might not be a bad idea to use the RTOS to manage ownership of the IFx register set at any given time.. (i.e. through a semaphore).

    But back to your first statement: "Unfortunately it does not look like the DMA is doing what I intend" what is it doing compared to what you wanted it to do?   Are you trying to chain your DMA requests together using the channel chaining function?  (i.e. secton 16.2.13 of the TRM?) 

  • Alan,

    I got a board setup w. a NI CAN bus monitor and tried the latest code that you'd posted.

    I'm not seeing any traffic on the CAN bus, with the monitor set to 500Kb/s (seems to match the HalCoGen settings).

    Does this match what you see or are you seeing some or parts of messages but the correct ones?

  • Hi Anthony,


    Unfortunately I've not had a chance to use the hardware breakpoint yet (I didn't know it existed, thanks for pointing out for me, it will be very useful!), I will work on it tomorrow.

    I use IF1 and IF2 as Halcogen has set them up, these functions seem to do what I need (despite a few worries over the possibility of being in an infinite loop when the CAN bus is busy) so I've decided to leave them as they are.


    Yes, the CAN does not seem to be triggering, using the dmaEnableInterrupt with BTC to try and see if the DMA transfers have gone as desired.

    adcREG1->GxBUF to canREG1->IF1DATx

    messageBox52 constant to canREG1->IF1NO

    0U into adcREG1->EVTOUT

    adcREG2->GxBUF to canREG1->IF1DATx

    etc

    The results from this are a bit confusing.

    -It looks like only the first byte of the ADC buffer is transmitted, despite BTC being set up as the interrupt

    -canREG1->IF1NO shows the constant of the second transfer (messageBox59) while it should be messageBox52

    -It looks like the interrupt does not work and the DMA continues to go through the chained channels through to the last.

    -This is despite the dmaEnableInterrupt being triggered in order by all 6 DMA channels.

    So to sum it up, it looks like the DMA is going through the channels without stopping, copying the first byte then triggering the next channel.  I'll look into this tomorrow.

    cheers,

    Alan

  • Hi Anthony,

    I'm having issues with the hardware breakpoints, as you can see in the image below, I've set up three breakpoints, the first is setup to trigger when 0xFFF7C0FC is accessed, in this case 0x00000000 is changed to 0x00000001.  The other two breakpoints are set in code each side of the hardware breakpoint.

    When running the code, only the two breakpoints set in the code halt the TMS570, the hardware breakpoint is ignored.

    Why is it not triggered, I've looked in the help section of CCS and there is not a section on it, the only part highlights the differences between SW and HW bps.

    Alan 

  • Alan,

    To catch a data access, you need a watchpoint.   Breakpoints are for program fetches (not data).

    It's the same window but you need to select HW Watchpoint instead of breakpoint.
    Should look like the picture above.

    Your other breakpoints are HW by the way, because the program is stored in flash.   SW breakpoints can only be set in RAM.

     

  • HI Anthony,


    I've tried setting up watchpoints but they do not seem to be working either, I've had them set up for adcREG2->GxBUF[0].BUF0 (0xFFF7C290) and for standard arrays, setting the watchpoint to both read and write has no effect.

    I'm at a loss as to why my does not work so I will ask a few questions.


    1- for the buffer for the ADC, is there any need to increment the addresses for the DMA as it seems the buffer is filled (all 8 addresses) by the same result each time it is read.
    2-Within the Halcogen DMA code what is meant by "uint32 CHCTRL;     /* next ctrl packet to be trigger + 1 */" if I want to trigger DMA_CH1 next do I need to state DMA_CH2 instead?

    3-As far as I can see to send a CAN message all that needs to be done is follow canTransmit()

    i.e.  transfer data to canREG1->IF1DATx (0xFFF7DD10), then transfer messageBox to canREG1->IF1NO (0xFFF7DD00) (8bit transfer)

    Cheers,

    Alan

  • Alan,

    I may have led you astray a bit - depending on the context.   Did you want to halt on a write by the CPU or a write by the DMA controller?

    The watchpoint that I showed in the screenshot of the CCS breakpoint tab is a CPU watchpoint.  It will catch the CPU performing a data access to the address (range) you specify.   It will not catch the DMA.

    To catch the DMA you need to use the watchpoint registers in the DMA controller.  These function about the same as the CPU watchpoint does, but they watch what the DMA is doing and there are fewer options.

    To get the DMA watchpoint working, pull out a TRM and find the DMA chapter.  Then go to these registers:

    So lets say you want to catch the DMA writing to 0xFFF7C290,  you could set the WPR register to 0xFFF7C290 and the WMR to 0x00000000.  This would setup precisely for address 0xFFF7C290.   Now if you wanted to set a range you could set some bits in WMR.   For example WMR = 0x0000 000F  would catch anything in the range of 0xFFF7C29x (x=0-F).

    Last write a 0x01 to DCTRL (DBGEN bit) and this will enable the watchpoint.  Then run the app.  It should halt just like it would on a breakpoint but probably it won't be a breakpoint.  You can check DBCTRL to confirm it halted due to a DMA watchpoint.  Bit 16 will be set if it did. 

    DBGEN, WPR, and WMR should be available through the "Registers" tab in CCS under the DMA controller peripheral.
    Or you can open a memory window to the DMA controller's registers and access that way.

     

     

  • Hi Anthony,

    I'm still having troubles


        dmaREG->WPR = 0xFFF7DD00;
        dmaREG->WMR=0x00000000;
        dmaREG->DCTRL = 0x00000001;

    does not seem to work, not interrupt occurs, despite data being written, tried on 3 different addresses taken from DMA channel setup.

    The DMA does not follow the order set (though this is hard to categorically state as I can't see the intermediate steps only the start and end state), DMA_CH0-5 are all set to high priority.

    Channel 0 is to copy data to canREG1->IF1DATx (triggered by adc2 EV group)

        adc2_dmaCTRLPKT.SADD        = (uint32)&(first[0]);
        adc2_dmaCTRLPKT.DADD      = 0xFFF7DD10;
        adc2_dmaCTRLPKT.CHCTRL    = DMA_CH1;
        adc2_dmaCTRLPKT.FRCNT     = 1;
        adc2_dmaCTRLPKT.ELCNT     = 7;
        adc2_dmaCTRLPKT.PORTASGN  = 4;
        adc2_dmaCTRLPKT.RDSIZE    = ACCESS_8_BIT;
        adc2_dmaCTRLPKT.WRSIZE    = ACCESS_8_BIT;
        adc2_dmaCTRLPKT.TTYPE     = BTC;
        adc2_dmaCTRLPKT.ADDMODERD = ADDR_INC1;
        adc2_dmaCTRLPKT.ADDMODEWR = ADDR_INC1;
        adc2_dmaCTRLPKT.AUTOINIT  = AUTOINIT_OFF;

        dmaSetCtrlPacket(DMA_CH0,adc2_dmaCTRLPKT);
        dmaSetChEnable(DMA_CH0, DMA_HW);
        dmaReqAssign(DMA_CH0,14U);

    Channel 1 copies 0x00870034 to canREG1->IF1NO and triggers DMA_CH2

    Channel 2 copies 0x00000001 to adcREG1->EVTSET (adcREG1->EVTOUT previously set to 0x00000001)

    Channel 3 (triggered by adcREG1->EVDMACR = 0x00000008;) copies adcREG1->BUF0 to canREG1->IF1DATx and triggers DMA_CH4

    Channel 4 copies 0x0087003B to canREG1->IF1NO and triggers DMA_CH5

    Channel 5 copies 0x00000001 to adcREG1->EVTCLR

    In main() i have the following:

        while(!adcIsConversionComplete(adcREG2,adcGROUP0));

        while(!canIsRxMessageArrived(canREG2,52U));
        //returns 0 until message arrives

        canGetData(canREG2,52U,can1_data);
        //data has arrived so......

        i++;

        while(!adcIsConversionComplete(adcREG1,adcGROUP0));

        while(!canIsRxMessageArrived(canREG2,59U));

        canGetData(canREG2,59U,can1_data);

    The code stops at while(!adcIsConversionComplete(adcREG1,adcGROUP0)); this should mean that the DMA has carried out DMA_CH1 and 2 but has failed at 3.

    When looking at the memory browser I can see the following:

    -Data from first[] has been copied to canREG1->IF1DATx

    -However the message received (canGetData(canREG2,52U,can1_data);) is empty

    -canREG1->IF1NO contains data from DMA_CH4, not DMA_CH1

    -adcREG1->EVTSET has not been set

    -adcREG1->EVTOUT has not changed to 1 so adc2 should not have been triggered

    My Questions:

    Why is DMA carrying out some transfers but ignoring others?

    How are those channels triggered if the preceding one has not been triggered?

    Why is the canREG1->IF1DATx not transferred if it is there?

    I have tested how the DMA treats the CAN as code and confirmed that it works via

    node->IF1DATx[s_canByteOrder[i]] = *data;

    *can_if1 = 0x00870001; where volatile unsigned int *can_if1 = (volatile unsigned int *)0xFFF7DD00;

    I have tested to see if adcREG1->EVTSET = 0x00000001, triggers the adc module and it does via

    adcREG1->EVTCLR = 0x00000001;

    adcStartConversion(adcREG1,adcGROUP0);

    adcREG1->EVTSET = 0x00000001;

    while(!adcIsConversionComplete(adcREG1, adcGROUP0));

    How does DMA work???  I see no logic in its operation.

    8625.HDK_DMA_ADC.zip

    Alan

  • Hi,

    I've simplified even more.


    RTI triggers DMA to write to 0xFFF7C108 (adcREG1->EVTSET) to cause a rising edge in "EVENT" which triggers ADC Event Group, the completion of this should trigger a second DMA channel which copies one array into another.


    The DMA debug is still not working

        dmaREG->GCTRL |= 0x00000300;
        dmaREG->WPR = 0xFFF7C108;
        dmaREG->WMR=0x00000000;


    Pausing the TMS570 before and after rtiNotification shows no change in any of the areas the DMA should be writing to.3858.HDK_DMA_EV.zip

    cheers,

    Alan

  • I've also tried GIOB0, but that does not work either.

    From the datasheet "the connection to the MibADC1 module trigger input is made from the output side of the input buffer" and "a trigger condition can be generated either by configuring the function as output onto the pad"

    3326.HDK_DMA_GPIO.zip


    What am I doing wrong?

  • Alan,

    Just focusing on your last post for the moment.

    So you're trying to use the GIOB0 pin to trigger the ADC event, is that right?

    I don't see the code that's toggling GIOB0.  The ADC is edge sensitive, so you need to create the edge on the GIOB0 pin and you need to do it after the ADC is configured.

    Or you could go into HalCoGen and change GIOB0 to an input and then drive an edge into GIOB0 from outside the chip.  But it appears you have GIOB0 as an output which means you really need to toggle GIOB0 in software to create the edge. 

     

  • Hi Anthony,

    The adc is meant to be triggered by the DMA changing the state of GIOB0 from a 0 to a 1 via dset register, rising edge.

    This is the same problem as discussed in the previous posts but instead of GIOB0 I had been using adc1evt.

    I tried GIOB0 to see if the problem is global and this proves it is.

    DMA has no effect on GPIO registers whether its for the gpio itself or any other peripheral set as a gpio.

    I'm asking why this is.

    Alan

  • In summary

    dmaREG->GCTRL correctly set to 0x00010300 in dmaEnable();

    dmaREG->DCTRL = 0x00000001; -> has no effect on register, remains 0x00000000.

    dmaREG->WPR = 0xFFF7BC60; -> has no effect on register, remains 0x00000000.

    Channel 0 set up as follows

        adc1_trig_dmaCTRLPKT.SADD      = (uint32)(&(adc1_trig));        //constant to set GIOB0 pin high (0x00000001)
        adc1_trig_dmaCTRLPKT.DADD      = 0xFFF7BC60;                //gioPORTB->SET (0xFFF7BC60)
        adc1_trig_dmaCTRLPKT.CHCTRL    = 0;                             //channel control
        adc1_trig_dmaCTRLPKT.FRCNT     = 1;                    //frame count
        adc1_trig_dmaCTRLPKT.ELCNT     = 1;                    //element count - single constant to copy
        adc1_trig_dmaCTRLPKT.ELDOFFSET = 0;                    //element destination offset
        adc1_trig_dmaCTRLPKT.ELSOFFSET = 0;                    //element source offset
        adc1_trig_dmaCTRLPKT.FRDOFFSET = 0;                    //frame destination offset
        adc1_trig_dmaCTRLPKT.FRSOFFSET = 0;                    //frame source offset
        adc1_trig_dmaCTRLPKT.PORTASGN  = 4;                    //port b
        adc1_trig_dmaCTRLPKT.RDSIZE    = ACCESS_32_BIT;                //read size
        adc1_trig_dmaCTRLPKT.WRSIZE    = ACCESS_32_BIT;                //write size
        adc1_trig_dmaCTRLPKT.TTYPE     = BLOCK_TRANSFER;            //transfer type
        adc1_trig_dmaCTRLPKT.ADDMODERD = ADDR_FIXED;                //address mode read
        adc1_trig_dmaCTRLPKT.ADDMODEWR = ADDR_FIXED;                //address mode write
        adc1_trig_dmaCTRLPKT.AUTOINIT  = AUTOINIT_OFF;                //autoinit

        dmaSetCtrlPacket(DMA_CH0,adc1_trig_dmaCTRLPKT);
        dmaSetChEnable(DMA_CH0, DMA_HW);
        dmaReqAssign(DMA_CH0,12);
        dmaSetPriority(DMA_CH0,HIGHPRIORITY);

    RTI is triggered (observed via rtiNotification();)


    DMA transfer does not happen and as the Debug has not initiated I'm unable to find out why.

    Alan

  • Hi Alan,

    Interesting.  I never tried adding code to the program to do these steps:

    dmaREG->DCTRL = 0x00000001; -> has no effect on register, remains 0x00000000.

    dmaREG->WPR = 0xFFF7BC60; -> has no effect on register, remains 0x00000000.

    I've always done this through the CCS GUI.  The TRM states

    Which I've always interpreted as 'you need to write to this register through the CCS GUI' but it could be interpreted as 'you have to have a debugger attached'.   Since you see your code executing but leaving '0' in the register I sense it is the former.   We can run this down and try to get a documentation clarification in.  But I believe you should have no problem opening the WP registers in a memory or register window in the debugger and changing their value this way.

    If you then want to put some automation behind that step - there's a way to handle this through scripting in CCS.  Rather than adding the WP to your applicaiton code.

    The reason that we're blocking the watchpoint this way I hope is obvious as you wouldn't want to accidentally have left a watchpoint setup in your program and then have it hit (and halt the CPU) when your app is deployed and there is no debugger attached.   So sorry it's a nusiance that it's protected but its done for a good reason.

    There's another thread on this forum about SCI and DMA, and DMA being big endian.   The HalCoGen headers have been changed to mostly use uint32 type for the register definitions and this isn't working well when the DMA needs to read/write uint16 or uint8 type data in the lower portion (bits 15:0) of the register since for these bits the address of the uint32 is different than that address of the uint16 or the uint8 that's located there.  Will need to look at your code to see if it might be something like this that's going on.   Here's one of the posts: http://e2e.ti.com/support/microcontrollers/hercules/f/312/p/312286/1134229.aspx#1134229

     

  • Hi Anthony,

    Thanks for the reply, I'll try setting the DMA debug tomorrow, I had not thought of doing it that way, I just assumed the only way to do it was via code.  I agree that through the GUI makes sense.

    As for the endianness, I'm pretty sure my project is setup for be32, either way I'm reading and writing the trigger in uint32 so the addressing should not be causing me a problem.

    Cheers,

    Alan

  • Hi Anthony,


    The debug is working now, however I'm not getting any movement from the DMA, the RTI does not seem to be triggering it.  Ive tried compare0 and 1 (12 & 13) but with no succes, i think it is a problem with how im setting up the dma, can you check?

    Cheers,

    Alan

  • Hi Alan,

    I'll try to spend some more time on this later today.  I got a little time last night and noticed that the code was stuck at the line of code that was polling the 'adcIsConversionComplete'.    I didn't see the GIOB[0] pin toggle on my scope and the GIOB port's DOUT register was 0x00000000.  

    I did poke a '0x00000001' into the DOUT register and this seemed to trigger the ADC because the code passed through the polling of 'adcIsConversionComplete' and onto reading the ADC data.    But I didn't see the pin toggle on the scope.  I think it might be a switch or jumper setting on my HDK though, because the DIN register indicated that the pin did toggle.

     EDIT:  Sorry Alan - I forgot to ask what you meant by the debug working.  Were you just able to write to the watchpoint registers, or did you write to them and have the DMA *halt* the CPU indicating that it read/wrote to the address you setup in the watchpoint?

  • Ok, it was my board, I had the ETH_ON switch set to on.  All the dip switches need to be OFF or GIOB[0] doesn't show up on the HDK's connectors.

    So I can see that the first part of the scheme isn't occurring.  The DMA write to the GIO register.  If I poke the GIO register directly now I see the pin go high and then this triggers the ADC.  Narrowing things down a bit.

     

  • Alan,

    Your DMA config looked OK at least as far as control registers (I didn't check the DMA control packets).

    The RTI seemed to be firing but I didn't see the PEND bit set in the DMA controller.

    Checking the RTI registers, I found that RTISETINT reads 0x0000 0001 - you can confirm this on your setup.
    That means the DMA reqeust isn't enabled.   I changed the value to 0x0000 0101 and then ran, and saw the GIOB[0] pin fire high as well as the program hit the 'exit()' which means main() completed.

    Sorry it took so long for me to see this.

    Here's the register description.   I know there is a diagram showing the interrupt request and DMA request in 'parallel' but they have separate enable bits.  I'll file a doc feedback on the diagram.

  • Hi Anthony,


    Thanks for sorting that out for me, that code works fine for me now, I've tried taking what Ive learnt on to the next part.  However I've noticed the software triggered DMA channels do not work as I'd expect.

    Firstly, they trigger as soon as they are setup via dmaSetCtrlPacket();

    Secondly, they do not trigger again.

    These two factors seem to be putting the chain out of sequence and for it to never recover.

    The HW channels trigger when they should but the SW channels remain inactive after the erroneous trigger at setup.


    This all can be seen in the project attached

    Channel 11 is triggered straight away, you can see 0xAA55AA55 in canREG1->IF1DATx

    If the previous channels had been triggered, then {'T','E','S','T','I','N','G','1'} would have been in canREG1->IF1DATx instead.

    3162.HDK_DMA_EV.zip

    Letting the code run on (after resetting adv_evt), the rti triggers again but SW channels are not triggered and the code stays waiting for the can message.

    Cheers,

    Alan

  • Alan,

    I think the software DMA channels trigger when you write to their "Enable" register.   So enable is more of a trigger.

    Are you perhaps writing to enable when you configure the channels.?

  • Hi Anthony,

    I think I made an incorrect assumption at the beginning here. 

    For example,

    channel 0 is DMA_HW with dmaCTRLPKT.CHCTRL    = 2, within its control packet.

    channel 1 is setup as DMA_SW and dmaCTRLPKT.CHCTRL    = 3, within its control packet.

    channel 2 is the last and also setup as DMA_SW.

    I assumed that hardware (say RTI) would trigger channel 0 and once its completed the frame (FRAME_TRANSFER) channel 1 would be triggered (internally?) by the DMA module and the same for channel 2.


    Re-reading the TRM after your post it seems this is not the case, SW and HW are treated in two totally separate ways by the function dmaSetChEnable which I found misleadign to the point of not being able to understand how the module works, I highly recommend stating that DMA_SW will be enabled(triggered) instantly.  Which of course is obvious if you're lucky and you've grabbed the right end of the stick.....

    So, as the only solution I can see I have set all the SW channels as the last HW request but use the DMA priority filtering to retain the correct order.

    How likely it is for the DMA to go out of sink?

    Cheers,

    Alan

  • Alan,

    If you can configure your DMA channels like this:

    Chan 0 - 1 element = 1st step of your transfer

    Chan 1 - 1 element = 2nd step ...

    Chan 2 - 1 element = 3rd step

    Then you can trigger them all from the same source.  The DMA will do the element from Chan0, then the element from Chan1, then from Chan2 and so on.  It won't violate that order.  Is that what you're asking when you ask about sync?

  • Hi Anthony,


    Thanks for sticking with me on this, finally got it all working, for some reason the DMA was not looping earlier today but it now continues until I stop it in my code.


    Yes that is what I was after, can't believe I wrote sink instead....


    As a side note, I still don't understand the function of dmaCTRLPKT.CHCTRL.

    Do you have to use dmaSetChEnable(); to tell the DMA module that it is DMA_SW or can you just set up the channel with dmaSetCtrlPacket() and if it is chained to another DMA_HW channel it is then triggered as DMA_SW anyway?

    Cheers,

    Alan