Menu

PIC DMA, and Array storage location in the PIC

Jim Henson
2021-07-13
2021-07-16
1 2 > >> (Page 1 of 2)
  • Jim Henson

    Jim Henson - 2021-07-13

    I'm struggling thru getting DMA working with a PIC18F27Q43, GCB Version 6.22.2290 or 04/06/2021:v0.98.07

    For making an arbitrary waveform generator I want to DMA from a 256 byte lookup in GPR data space to the DAC. Source size is 256, destination size is 1. I believe I have DMA mostly working, which equates to not working. I'm pretty sure of my DMA configuration register settings, triggered from either a timer or from IOC, but... I've scrubbed the Microchip DAC App Notes and the MPLAB Code Configurator, but not successfully translated that into GCB.

    Does anyone have known operational GCB sample source for starting the DMA, for GPR to peripheral?

    I can successfully send values from an array to the DAC from program control, with the data stored in an array:
    ' #Define WaveArraySize 256
    ' Dim WaveArray(WaveArraySize) AT 0x1000

    Where in GPR data space does "AT 0x1000" refer to? How does "AT 0x1000" correspond to an entry in the DMA Source Start Address Registers?

    Where may I store data in GPR without stepping on GCB variables? Contiguous memory seems to start at bank 6 in GPR.

    Thanks Mucho,
    Jim

     
  • Anobium

    Anobium - 2021-07-13

    Should work.

    Can you share your code? I can then see where the memory is being defined ( re @0x1000 ).

    Post a link to the AppNote please.

    Cheers

     
  • Jim Henson

    Jim Henson - 2021-07-13

    This attached code works, where the array is stored in the PIC GPR space is what I can't find.

    I'd like to load waveform patterns from tables into the array, eventually to be fed to the DAC by DMA. The DMA source pointer DMAnSPTR is three 8 bit registers, PIC18F27Q42 data sheet page 292.

    Thanks, Jim

     
  • Anobium

    Anobium - 2021-07-13

    Looking at the now.

    As MPLAB-IDE is NOT simulating this chip correctly (well the SFRs are being updated!) I am having to use legacy debugging.

    BRB

     
  • Jim Henson

    Jim Henson - 2021-07-13

    Thanks for your effort!
    Sleepy time...

     
  • Anobium

    Anobium - 2021-07-13

    MPLAB-IDE shows the chip to be working at expected however... I have just asked Microchump 'how do I view in the debugger the Buffer RAM?' This is important as we need to see what is happening during the DMA events.


    Where in GPR data space does "AT 0x1000" refer to? How does "AT 0x1000" correspond to an entry in the DMA Source Start Address Registers?

    The AT 0x1000 will create the array at address 0x1000.
    The DMA DMA Source Start Address Registers would have to point to this address.

    Where may I store data in GPR without stepping on GCB variables? Contiguous memory seems to start at bank 6 in GPR.

    Not sure what you are try to achieve. Explain.


    What is the source concept/example for this project ? I have seen a few DMA examples - are you using one of the existing example? Please post a link.

     
  • Anobium

    Anobium - 2021-07-13

    Consider this a gift from Santa.

    A solution that will give you a range of 245Hz to 31kHz. Change the value of timer0 ( see lines 43-45) to change the frequency. Use SetTimer 0, 1 to change the frequency but if you want slower frequencies then change the InitTimer pre and post values.

    The code.

    1. Loads the array from the table
    2. Shows the array values using conventional DAC
    3. Load the timer
    4. Setup DMA
    5. Loop forever

    The DMA is setup like this/

    1. Select the DMA channel
    2. Set the source mode to 'SMODE incremented' - so, it will increment thru the 256 bytes of SRAM memory.
    3. Set the source size and address. I used an alias to show how easy this is. I then used '@' to tell the compiler to use the address of the SRAM.
    4. Set the destination size and address. . I used '@' to tell the compiler to use the address of the DAC.
    5. Set the trigger source as TIMER0.
    6. Start the DMA

    So, every time Timer0 overflows the DMA is triggered. It increments thru the 256 of SRAM moving direct to the DAC.


    You can develop this into a mega solution. Different wave forms, adc to set the frequency etc.

    Seems to work ok.

    Enjoy

     

    Last edit: Anobium 2021-07-13
  • Jim Henson

    Jim Henson - 2021-07-13

    Hi Evan,

    The example I sent does work, My Oscope shows a sine wave coming out port B.3, but that isn't using DMA.

    I've seen lots of the DMA examples as you posted, but I'm not confident they are from operational code. Other DMA examples around the internet are basically wrapped copies of the example you posted here, which comes from page 284 of the data sheet DS40002147D-1903101.pdf.

    I'd like to focus for now on memory allocation.

    The 18F27Q43 has 8192 bytes of Data SRAM organized as 32 pages of 256 bytes each, depicted in figure 9.3 on page 71 of the data sheet.

    Where does GCB store its operational data (ie transients) and dimensioned variables?

    I suspect GCB variable storage area doesn't start at GPR physical address zero, or users could write code that would step on SFR space.

    That is, Dim WaveArray(WaveArraySize) AT 0x1000 would be in bank 2 of SFRs, which I don't think is "user" GPR memory. Dim Array(Large) AT 0x0 might be disastrous!

    Also, GCB PEEK and POKE don't seem to use the same addressing scheme as the DIM "AT 0x1000". That is, OutputVariable = Peek (0x1000) doesn't yield numbers I store in the WaveArray AT 0x1000. I plan to examine that more thoroughly.

    Thanks, Jim

     
  • Anobium

    Anobium - 2021-07-13

    @Jim, the code posted works using DMA and it shows the method to be used. This method is the same a XC8 only the address has to use @ not &, also, show in the datasheet.

    Memory allocation is NOT required. Simply use @ to the correct register,

    There a no transient variables - all variables are explicit in the ASM.

    Don't suspect that. The memory address starts at 0x500 and ends at the end point in memory for each specific q43 chip size.

    When using improper memory addresses the compiler will issue a warning. Just let the compiler handle memory locations. The compiler correct handles banks selection.

    PEEK and POKE do not use the same scheme as DIM AT. Incorrect. PEEK and POKE use memory addresses, as does DIM AT. But, I will repeat.... let GCB do this stuff for you.

    Please study the code https://sourceforge.net/p/gcbasic/discussion/579125/thread/aa536679df/7166/attachment/18F27Q43_DAC_Test_071321b.gcb It shows the correct method.

     
  • Jim Henson

    Jim Henson - 2021-07-13

    I'm about 2 weeks deep into DMA on this PIC! I'm at the point of dreaming DMA registers at night, so I'm pretty familiar with the DMA setup and control process. I just can't get DMA to run right with GCB. And I think I've seen every PIC DMA app note and code example on earth. I have my code well "instrumented" and can see things happening, just not DMA of the values "AT 0x1000".

    I will share that code with you, but I want to understand memory allocation first so I know where I am pointing the DMA source registers. I've seen so much code that is" supposed to work" that I don't want to post code that I know doesn't work right.

    Thanks, Jim

     
    • Anobium

      Anobium - 2021-07-13
      1. Examine the code. It works! I would not be making it up. The code is very simple.
      2. You can put the array anyway in valid memory using AT and the @ will handle. In the code I posted today I use AT 0X600... remove it. It still works!
       

      Last edit: Anobium 2021-07-13
  • Anobium

    Anobium - 2021-07-13

    Memory Allocation

    This note discusses the allocation of variables to RAM ( GPR, SRAM etc).

    Variables in Great Cow BASIC can be bits, bytes, words, integers, longs, arrays or reals. This document will NOT address reals (as these are developmental variables only).

    Variables can also be defined as Aliases - this is discussed later.

    Basic allocation

    Variables of the type byte, word, integer, longs are placed in RAM using the following simple rules.

    1. A RAM memory location is automatically assigned starting at the first available memory location.
    2. The first memory location is first RAM location as defined in the chip datasheet.
    3. Once a variable is allocated the RAM location is marked as used and this specific location can be reviewed in the ASM source.
    4. Bytes use a single RAM location, words two RAM locations, integer and longs four RAM locations.
    5. Subsequent variables of type byte, word, integer, longs are placed in RAM at the next available RAM location.

    Variables of the array type are placed in RAM using the following simple rules.

    1. A RAM memory location is automatically assigned from the end of RAM less the size of the array.
    2. The last memory location is last RAM location as defined in the chip datasheet.
    3. Once an array is allocated the RAM location is marked as used and the start of the array RAM location can be reviewed in the ASM source.
    4. Subsequent variables of type array in RAM at the next available RAM location subtracted from the start the of previous RAM location minus the size of this next array.

    Variables of the bit type are placed in RAM using the following simple rules.

    1. Bit memory location is automatically assigned to the first bit with the creation of a BYTE variable at a RAM memory location that is automatically assigned starting at the first available memory location. This byte can handle 8 bits.
    2. Once a bit is allocated the byte is marked as used and this specific location can be reviewed in the ASM source.
    3. Subsequent bits are allocation either to an existing byte variable, or when 8 bits are allocated to an existing byte variable another byte variable will be created.

    AT allocation

    The Dim variable command can be used to instruct Great Cow BASIC to allocate variables at a specific memory location using AT.

    The compiler will inspect the provide AT memory location and if the memory location is already used ( by an existing variable), lower than the minimum memory location or greater than the maximum memory location an error will be issued.

    Variable Aliases

    Variable can be defined as aliases. Aliases are used to refer to existing memory locations SFR or RAM and aliases can be used to construct other variables. Constructed variables can be a mix ( or not ) of SFR or RAM. These are useful for joining predefined byte variables together to form a word/long variable.

    Aliases are not like pointers in many languages - they must always refer to an existing variable or variables and cannot be changed.

    When setting a register/variable bit ( i.e my_variable.my_bit_address_variable ) and using a alias for the variable then you must ensure the bytes that construct the variable are consecutive.

    Aliases are shown in the ASM in the ;ALIAS VARIABLES section

    The coding approach should be to DIMension the variable (word, integer, or long) first, then create the byte aliases:

        Dim my_variable as LONG
        Dim ByteOne   as Byte alias my_variable_E
        Dim ByteTwo   as Byte alias my_variable_U
        Dim ByteThree as Byte alias my_variable_H
        Dim ByteFour  as Byte alias my_variable
    
        Dim my_bit_address_variable as Byte
        my_bit_address_variable = 23
    
        'set the bit in the variable
        my_variable.my_bit_address_variable = 1
    
        'then, use the four byte variables as you need to.
    

    To set a series of registers that are not consecutive, it is recommended to use a mask variable then apply it to the registers:

    Dim my_variable as LONG
    Dim my_bit_address_variable as Byte
    my_bit_address_variable = 23
    
    'set the bit in the variable
    my_variable.my_bit_address_variable = 1
    
    porta =  my_variable_E
    portb =  my_variable_E
    portc =  my_variable_E
    portd =  my_variable_E
    

    Good Practice

    Let the compiler allocate memory locations. In all my time using Great Cow BASIC I have never forced a memory location using the 'AT' instruction.

    Memory Specification

    All memory specifics like size, lower and upper addresses are specified in the chip specific dat file.

    The dat file details should be reviewed in PICINFO. See the CHIPDATA tab for RAM and MaxAddress.

    A simple calculation is MaxAddress - RAM +1 = the 'first memory address'. And, 'first memory address' + RAM -1 = 'the last memory address.

    This can be confirmed by review the DAT file. See the section [FreeRAM] for the start and end of RAM.

    The dat file also has a [NoBankRAM]. NoBankRAM is somewhat misnamed - it is used for the defintion of (any) access bank locations If a memory location is defined in both NoBankRAM and FreeRAM, then the compiler knows that it is access bank RAM.
    If an SFR location is in one of the NoBankRAM ranges, then the compiler knows not to do any bank selection when accessing that register.

    [NoBankRAM] section includes two ranges, one for access bank RAM, one for access bank SFRs.
    The first range MUST be the ACCESS RAM range
    The first range is the FAST SFR range

    If there are no ranges defined in NoBankRAM, the compiler will try to guess them.
    On 18Fs, it will guess based on where the lowest SFR is, and from what the total RAM on the chip is. If there's only one range defined. in the NoBankRAM locations, the compiler will assume that is the range for the RAM, and then will guess where the range for the access bank SFRs is.

     

    Last edit: Anobium 2021-07-13
  • William Roth

    William Roth - 2021-07-13

    It works!

    I loaded up Evan's code and get a decent sine wave at ~ 32Khz.

    Since this is an unbuffered DAC output, it is best read with a 10:1 or higher probe to eliminate signal distortion introduced by the scope. (Looks bad with 1:1)

    I have a future project that needs approximately 60 Hz sine wave. So with a simple change to the timer setup and an adjustment to OSCTUNE I was able to get 59.939 Hz.

    Here are the changes needed in order to get 59.939Hz. (Assumes a 64Mhz System Clock)

     OSCTUNE = 0b111010
      InitTimer0 Osc, PRE0_64 + TMR0_FOSC4 ,  POST0_8
    

    Note: Changing OSCTUNE will slightly affect "wait" times , baud rates, etc.
    In this case by about .8%.

    William

     
    • Anobium

      Anobium - 2021-07-13

      @williamroth WONDERFUL! EVEN SLOWER AND BETTER

       

      Last edit: Anobium 2021-07-13
  • Jim Henson

    Jim Henson - 2021-07-13

    Thank You! Thank You!

    While many of MY "problems" are yet to be resolved, this was the fix for my code problem:
    Dim addressdummy as byte
    Dim DMAnSS as long ALIAS addressdummy, DMAnSSAU, DMAnSSAH, DMAnSSAL
    DMAnSS = @WaveArray

    I was loading the three regs DMAnSS U,H, and L separately. Not sure why it's different, but I bet I was pointing the DMA source to never-never land. The @WaveArray is smarter than I am.
    What a lovely sine wave now!

    You are right on about the mega solution. The wave tables are instrument voice waveforms, and thanks to DMA, the PIC can manage envelope and other "slow" activities. The DMA pacing comes from IOC on a pin from a PLL, 256 times the note frequency. While ROM/RAM voiced synthesizers are oh-so 90's, this is a fun wheel to reinvent. With the ADCC module, sampled voices are a real possibility. A Casio SK-5 on one $2 chip? Monophonic though...

    Also playing with the Numerically Controlled Oscillator Module to generate note frequencies much more accurately than the good-old timers. Not that I can hear the difference...

    My next broken code to fix is setting the arbitration priority for the DMA. My many HSERPRINTs for debugging the DMA process introduce glitches into the output waveform.

    Thanks mucho,
    Jim

     
  • Jim Henson

    Jim Henson - 2021-07-14

    Hey William,

    If your 60 hz needs more precision, the Numerically Controlled Oscillator Module will get you there!

    Faaar more range and precision than the standard timers. Configuration is a snap, based on my first attempt actually working. ;=} I believe you have to PPS the output to a pin, as I don't see NCOx shown in the pin allocation tables in the PIC18FxxQxx data sheets.

    '#startup InitPPS, 85
    Sub InitPPS
    RC0PPS = 0x3F ' NCO1 > RC0 This sets the PPS Output Signal Routing
    End Sub

    Set the pin as an output: Dir PortC.0 out
    Routing NCO1 to DMA: DMANSIRQ = 0x33

    The 18FxxQxx PICs are full of treasures!

    NCO App Note: https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/90003131A.pdf

    Jim

     
    • Anobium

      Anobium - 2021-07-14

      @jim,

      NCO is across a number of PICs.

      Do you have a moment to create a working demo that I use in the demos?

      I think this will be very useful. Take the code I posted, rip out all that is not need and then put the NCO back in. I am not sure that the the few lines of setting RC0PSS and setting the DMAnSIRQ will actually work if someone follows this thread in the coming months/years.

      @-)

       
  • Jim Henson

    Jim Henson - 2021-07-14

    Hi Evan,

    I can do that this evening. For now, the attached works with DMA, DAC and NCO1

    Thanks, Jim

     
    • Anobium

      Anobium - 2021-07-14

      An improvement to your code showing how to use @ against an ALIAS to make the code easy to read/follow.

      See lines 60-62 to set the Destination Start Address. This method will ensure that any address is handled correctly.

       
  • Jim Henson

    Jim Henson - 2021-07-15

    Hello Evan,

    In the second demo, how does the table data get stored into program flash memory?

    Attached is the second demo with NCO instead of timer 0, tested.

    Thanks, Jim

     
    • Anobium

      Anobium - 2021-07-15

      In the second demo, how does the table data get stored into program flash memory?

      Lines 21-23 - you have to read the WaveTableSize in anyway. And, this then loads the full table into PROGMEM at @TableWave (note the TABLE prefix to the table data called Wave).


      Thanks for the demo. I will test and publish!

       
      • Jim Henson

        Jim Henson - 2021-07-15

        What points the destination to program flash vs GPR Ram?

         
        • Anobium

          Anobium - 2021-07-15

          One of the bits in DMAnCONx as follows in the programs.

          SMR Program Flash

          ' DMODE unchanged; DSTP not cleared; SMR Program Flash; SMODE incremented; SSTP not cleared;
               DMAnCON1 = 0x0A
          

          verses

          SMR GPR

            ' DMODE unchanged, DSTP not cleared, SMR GPR, SMODE incremented, SSTP not cleared
               DMAnCON1 = 0x02
          
           
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.