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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
Loads the array from the table
Shows the array values using conventional DAC
Load the timer
Setup DMA
Loop forever
The DMA is setup like this/
Select the DMA channel
Set the source mode to 'SMODE incremented' - so, it will increment thru the 256 bytes of SRAM memory.
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.
Set the destination size and address. . I used '@' to tell the compiler to use the address of the DAC.
Set the trigger source as TIMER0.
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.
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@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.
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
A RAM memory location is automatically assigned starting at the first available memory location.
The first memory location is first RAM location as defined in the chip datasheet.
Once a variable is allocated the RAM location is marked as used and this specific location can be reviewed in the ASM source.
Bytes use a single RAM location, words two RAM locations, integer and longs four RAM locations.
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.
A RAM memory location is automatically assigned from the end of RAM less the size of the array.
The last memory location is last RAM location as defined in the chip datasheet.
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.
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.
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.
Once a bit is allocated the byte is marked as used and this specific location can be reviewed in the ASM source.
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:
Dimmy_variableasLONGDimByteOneasBytealiasmy_variable_EDimByteTwoasBytealiasmy_variable_UDimByteThreeasBytealiasmy_variable_HDimByteFourasBytealiasmy_variableDimmy_bit_address_variableasBytemy_bit_address_variable=23'set the bit in the variablemy_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:
Dimmy_variableasLONGDimmy_bit_address_variableasBytemy_bit_address_variable=23'set the bit in the variablemy_variable.my_bit_address_variable=1porta=my_variable_Eportb=my_variable_Eportc=my_variable_Eportd=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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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)
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
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.
@-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
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
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
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
Thanks for your effort!
Sleepy time...
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.
The AT 0x1000 will create the array at address 0x1000.
The DMA DMA Source Start Address Registers would have to point to this address.
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.
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.
The DMA is setup like this/
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
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
@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.
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
Last edit: 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.
Variables of the array type are placed in RAM using the following simple rules.
Variables of the bit type are placed in RAM using the following simple rules.
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:
To set a series of registers that are not consecutive, it is recommended to use a mask variable then apply it to the registers:
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
I have moved the Memory Allocation post to the Help. The information must not be lost.
Please review/edit the online version @ https://github.com/Anobium/Great-Cow-BASIC-Help/blob/master/source/variableassignment.adoc
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)
Note: Changing OSCTUNE will slightly affect "wait" times , baud rates, etc.
In this case by about .8%.
William
@williamroth WONDERFUL! EVEN SLOWER AND BETTER
Last edit: Anobium 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
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
@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,
Two demos both have the same output but they use different techniques as the Sine Data source.
The second demonstration saves 261 bytes of RAM. It is clearly a smaller PROGMEM - so, this is worth looking at to save that precious RAM.
https://github.com/Anobium/Great-Cow-BASIC-Demonstration-Sources/blob/master/DMA_Solutions/18F27Q43_ARRAY_DMA_DAC.gcb
https://github.com/Anobium/Great-Cow-BASIC-Demonstration-Sources/blob/master/DMA_Solutions/18F27Q43_TABLE_DMA_DAC.gcb
Hi Evan,
I can do that this evening. For now, the attached works with DMA, DAC and NCO1
Thanks, Jim
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.
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
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!
What points the destination to program flash vs GPR Ram?
One of the bits in DMAnCONx as follows in the programs.
SMR Program Flash
verses
SMR GPR