I ran the sine wave example that @Ariba posted and it works fine on my P2 Eval board so I know that my hardware is working. Now I just have to get *my* code working!
Here's a very basic stereo audio example code in pasm...
CON
L_PIN = 0
R_PIN = 1
SYSTEM_CLOCK = 250000000
SAMPLE_RATE = 250000
'DAC_MODE = %00001_0 ' DAC 8-bit noise
'DAC_MODE = %00010_0 ' DAC 16-bit dither, noise
DAC_MODE = %00011_0 ' DAC 16-bit dither, PWM
DIR_MODE = %01 ' Output enabled, overrides DIR
INIT_8BIT_DAC_VALUE = 128
'ANALOG_OUT_MODE = %10100 ' 990 ohm, 3.3V DAC mode
'ANALOG_OUT_MODE = %10101 ' 600 ohm, 2.0V DAC mode
'ANALOG_OUT_MODE = %10110 ' 123 ohm, 3.3V DAC mode
ANALOG_OUT_MODE = %10111 ' 75 ohm, 2.0V DAC mode
SMARTPIN_DAC_MODE = (ANALOG_OUT_MODE << 16) | (INIT_8BIT_DAC_VALUE << 8) | (DIR_MODE << 6) | DAC_MODE
SAMPLE_PERIOD = SYSTEM_CLOCK / SAMPLE_RATE 'CPU cycles between sample updates
DAT
org
wrpin ##SMARTPIN_DAC_MODE, #L_PIN ' Config smartpin DAC mode on left pin
wrpin ##SMARTPIN_DAC_MODE, #R_PIN ' Config smartpin DAC mode on right pin
wxpin ##SAMPLE_PERIOD, #L_PIN ' Set sample period for left audio channel
wxpin ##SAMPLE_PERIOD, #R_PIN ' Set sample period for right audio channel
dirh #L_PIN ' Enable smartpin DAC mode on left pin
dirh #R_PIN ' Enable smartpin DAC mode on right pin
setse1 #%001_000000 | L_PIN ' Event triggered every new sample period (when "left in pin rises")
loop
wypin sawWave, #L_PIN ' Output sample on left channel
wypin sawWave, #R_PIN ' Output sample on right channel
waitse1 ' Wait for smart pin NCO wrap, new period
add sawWave, #1
jmp #loop
sawWave res 1
I tried this slightly modified version of your code but all I get are pops on my speaker about every two seconds. What did I do wrong? My main changes were using the output pins for the A/V accessory to the P2 Eval board and stripping out code that was commented out in your version.
CON
L_PIN = 14
R_PIN = 15
_clkfreq = 250_000_000
SAMPLE_RATE = 250_000
DAC_MODE = %00011_0 ' DAC 16-bit dither, PWM
DIR_MODE = %01 ' Output enabled, overrides DIR
INIT_8BIT_DAC_VALUE = 128
ANALOG_OUT_MODE = %10101 ' 600 ohm, 2.0V DAC mode
SMARTPIN_DAC_MODE = (ANALOG_OUT_MODE << 16) | (INIT_8BIT_DAC_VALUE << 8) | (DIR_MODE << 6) | DAC_MODE
SAMPLE_PERIOD = _clkfreq / SAMPLE_RATE 'CPU cycles between sample updates
DAT
org
wrpin ##SMARTPIN_DAC_MODE, #L_PIN ' Config smartpin DAC mode on left pin
wrpin ##SMARTPIN_DAC_MODE, #R_PIN ' Config smartpin DAC mode on right pin
wxpin ##SAMPLE_PERIOD, #L_PIN ' Set sample period for left audio channel
wxpin ##SAMPLE_PERIOD, #R_PIN ' Set sample period for right audio channel
dirh #L_PIN ' Enable smartpin DAC mode on left pin
dirh #R_PIN ' Enable smartpin DAC mode on right pin
setse1 #%001_000000 | L_PIN ' Event triggered every new sample period (when "left in pin rises")
loop
wypin sawWave, #L_PIN ' Output sample on left channel
wypin sawWave, #R_PIN ' Output sample on right channel
waitse1 ' Wait for smart pin NCO wrap, new period
add sawWave, #1
jmp #loop
sawWave res 1
I'm assuming that in the p_dac_dither_rnd mode, I write a signed 16 bit value to Y to set the output level. Is that correct? I'm having a hard time understanding the Smartpin description.
For example, the pin mode I'm using is described like this:
%00010 and DAC_MODE = DAC 16-bit with pseudo-random dither
This mode overrides P[7:0] to feed the pin's 8-bit DAC with pseudo-randomly-dithered data on every clock. P[12:10] must be set to %101 to configure the low-level pin for DAC output.
First, what is "P"? and the description talks about overriding P[7:0] which is only 8 bits but the name of the mode is "DAC 16-bit". Do I write 8 bits to the Y register or 16?
Note: The sysclock frequency is not being set for you when in pure pasm2 assembly mode. You have to do your own code for it. Default is usually RCFAST.
Note: The sysclock frequency is not being set for you when in pure pasm2 assembly mode. You have to do your own code for it. Default is usually RCFAST.
Ah, okay. That is likely my problem. I'm probably "hearing" a 2 hz sawtooth. What's the official PASM incantation to set the clock frequency?
P field is a portion of the whole 32 bits passed in D operand of WRPIN. It's the low level custom pin mode settings. The field size is 13 bits, numbered as P[12:0]. The upper bits form the mode, with the lower bits the parameters. Also referenced as M[12:0] in the pad I/O sheet.
Y register is a 32-bit smartpin parameter. Some smartpin modes don't use all 32-bits. In this case it's unsigned 16-bit only. The upper 8 bits of Y are used directly for the DAC output. The lower 8 bits are compared against an 8-bit timer/RND to produce the extended dither.
P field is a portion of the whole 32 bits passed in D operand of WRPIN. It's the low level custom pin mode settings. The field size is 13 bits, numbered as P[12:0]. The upper bits form the mode, with the lower bits the parameters. Also referenced as M[12:0] in the pad I/O sheet.
Y register is a 32-bit smartpin parameter. Some smartpin modes don't use all 32-bits. In this case it's unsigned 16-bit only. The upper 8 bits of Y are used directly for the DAC output. The lower 8 bits are compared against an 8-bit timer/RND to produce the extended dither.
The saw wave steps through all the 65536 steps of the 16 bit DAC's. (add #1) This means you that you will get a frequency of 250000 / 65536 = 3.81 Hz if the system clock is 250 Mhz. The constant doesn't reflect the real system clock. Change the add value, constants or system clock to get other results.
...
You are going to be 'listening to your power supplies' in a direct P2-to-Analog Audio design, with both DAC and Fast PWM.
On the P2, every 4 IO pins can have their own clean supply voltage connected.
The sample rate of a P2 16bit DAC can go much higher than usual I2S ICs. But they mostly have 24bit resolution. So it depends what exactly you want to do, I find the audio quality of the P2 DACs very good.
While I use dual 3.3V LDOs to A & B ports after my 3.6V switcher to clean up the ripple and improve transient response etc, I am thinking I should allow for resistors or maybe ferrite beads in each I/O group in conjunction with the bypass caps to help filter out any supply noise. Effective enough or not, they are just another 0603 that can be substituted and experimented with.
So far I have been impressed with the DACs for audio.
On the P2 Eval board we have separate LDO's for each set of 8 pins. This has worked out really well, as there is no discernible noise in the audio spectrum from those LDO's. Well, none that I've noticed.
The highest-quality DAC setting for audio is 75-ohm PWM-dither mode with a multiple-of-256-clocks update period.
The saw wave steps through all the 65536 steps of the 16 bit DAC's. (add #1) This means you that you will get a frequency of 250000 / 65536 = 3.81 Hz if the system clock is 250 Mhz. The constant doesn't reflect the real system clock. Change the add value, constants or system clock to get other results.
Duh. I should have noticed that. The waveform isn't in the audible range. I tried changing the increment and, as you suggest, it works fine.
I know this doesn't address your problem directly, but maybe removing some stuff will help isolate the issue:
FlexC will default to 160Mhz for P2 if you don't do any of the p2es_clock.h/_clkset stuff. Also, you can call _clockfreq() to read the frequency when you don't use the p2es_clock.h/_clkset stuff (you can use it if you do also).
Also, have you looked at the listing file for the C version, might reveal some clues.
@"David Betz" : I don't see the clock being set in the pure assembly version. You have a _clkfreq declaration, but that's only going to have an effect if there's some Spin code: in pure assembly (if the file is DAT only) then what you see is what you get. So perhaps there's a timing issue?
Another difference is that the PASM sawWave variable is a full 32 bits, whereas the C output variable is only 16 bits.
@"David Betz" : I don't see the clock being set in the pure assembly version. You have a _clkfreq declaration, but that's only going to have an effect if there's some Spin code: in pure assembly (if the file is DAT only) then what you see is what you get. So perhaps there's a timing issue?
Another difference is that the PASM sawWave variable is a full 32 bits, whereas the C output variable is only 16 bits.
I'll try changing the variable size to 32 bits. I've already tried the code with and without the _clkset call with no observable difference in the behavior.
Edit: It still doesn't seem to work after I changed the output variable 32 bits. I guess I should look at the generated code to see if I can figure out what's going wrong.
I'll try changing the variable size to 32 bits. I've already tried the code with and without the _clkset call with no observable difference in the behavior.
Perhaps I wasn't clear. The C version will always have the clock set to 160 MHz, even without an explicit _clkset call, because the C startup code does this.
The assembly code has no clock frequency setting, and so it's going to be running at RCFAST speed (25 MHz) instead.
The C version also does not include the INIT_8BIT_DAC_VALUE bit.
Also, Ariba, I tried including propeller2.h in the C version and it doesn't appear to change anything... I was wrong, including propeller2.h makes it actually work with the sawtooth output.
Comments
For example, the pin mode I'm using is described like this:
First, what is "P"? and the description talks about overriding P[7:0] which is only 8 bits but the name of the mode is "DAC 16-bit". Do I write 8 bits to the Y register or 16?
Note: The sysclock frequency is not being set for you when in pure pasm2 assembly mode. You have to do your own code for it. Default is usually RCFAST.
Y register is a 32-bit smartpin parameter. Some smartpin modes don't use all 32-bits. In this case it's unsigned 16-bit only. The upper 8 bits of Y are used directly for the DAC output. The lower 8 bits are compared against an 8-bit timer/RND to produce the extended dither.
You might want to check out Ariba's spin code just below too.
EDIT: And here's a document type write up of PAD_IO_Modes sheet - https://forums.parallax.com/discussion/comment/1452036/#Comment_1452036
And a block diagram - https://forums.parallax.com/discussion/171420/smartpin-diagram/p1
I'll have to port that to pasm2 now ...
You are going to be 'listening to your power supplies' in a direct P2-to-Analog Audio design, with both DAC and Fast PWM.
The saw wave steps through all the 65536 steps of the 16 bit DAC's. (add #1) This means you that you will get a frequency of 250000 / 65536 = 3.81 Hz if the system clock is 250 Mhz. The constant doesn't reflect the real system clock. Change the add value, constants or system clock to get other results.
On the P2, every 4 IO pins can have their own clean supply voltage connected.
The sample rate of a P2 16bit DAC can go much higher than usual I2S ICs. But they mostly have 24bit resolution. So it depends what exactly you want to do, I find the audio quality of the P2 DACs very good.
So far I have been impressed with the DACs for audio.
The highest-quality DAC setting for audio is 75-ohm PWM-dither mode with a multiple-of-256-clocks update period.
Duh. I should have noticed that. The waveform isn't in the audible range. I tried changing the increment and, as you suggest, it works fine.
This works:
but this doesn't:
Aren't they doing pretty much the same thing? Why doesn't the C code work?
You need to include "propeller.h" and call clkset() at begin.
See "cdemo.c"
Andy
FlexC will default to 160Mhz for P2 if you don't do any of the p2es_clock.h/_clkset stuff. Also, you can call _clockfreq() to read the frequency when you don't use the p2es_clock.h/_clkset stuff (you can use it if you do also).
Also, have you looked at the listing file for the C version, might reveal some clues.
Another difference is that the PASM sawWave variable is a full 32 bits, whereas the C output variable is only 16 bits.
Edit: It still doesn't seem to work after I changed the output variable 32 bits. I guess I should look at the generated code to see if I can figure out what's going wrong.
If I include the "propeller2.h" file, it works, but if this file is not included, there is no error message.
The assembly code has no clock frequency setting, and so it's going to be running at RCFAST speed (25 MHz) instead.
Do you mean the code functions correctly if "propeller2.h" is included, but not if it is not included?
Or do you mean that you're surprised that there are no errors because things like _wypin are not declared?
If it's the second, then it's just because _wypin and co. are builtin functions in FlexC and so don't actually need to be declared.
Also, Ariba, I tried including propeller2.h in the C version and it doesn't appear to change anything... I was wrong, including propeller2.h makes it actually work with the sawtooth output.
Both of them.
Something is missing if propeller2.h is not included, but the compiler will not say me what ;-)
Andy
Yep that's it. If I swap the order of params on David's _wypin() call then it works without the propeller2.h