PDA

View Full Version : Darrels interrupts and multiple SOUND statements, will it work?



CuriousOne
- 12th January 2015, 07:46
As it's known, you can have several interrupts with Darrels interrupts. What if I use say 4 interrupts, and use SOUND statement in each to output sound on separate pin, then connect the pins via resistors to same speaker, so I can get polyphonic music, or say music and drumkit line? will it work? are there any limits for specific statements vs interrupts?

richard
- 12th January 2015, 08:56
a sound command will lock the interrupt that its in until it completes . interrupts aren't interruptible (except on pic18 hi/lo priority) . sound commands will be sequential no matter how you go about it
you would need a pic multi tasking os like RTOS to get anywhere close to that

HenrikOlsson
- 12th January 2015, 09:04
The processor can only do one thing at the time. It can't exectute two SOUND commands simultanously no matter where you place them.
If you put a SOUND command in ONE interrupt handler that SOUND command will block all other interrupts while executing unless one of the other interrupts have a higher priority* than the one currently executing, in which case the one currently executing will be "halted" untill the ISR with higher priority is finished.

* PIC18 have two interrupt priorities.

You could use a PIC with multiple PWM modules and something like a 1ms background tick to turn them on/off.

EDIT: Richard beat me to it....

CuriousOne
- 12th January 2015, 09:25
Yes I already use 16F876's PWM channels to have 2 note polyphony, but I'd like to have more on simpler chips (say 12F683).

Here's 16F628A doing not only stereo polyphony, but color graphics too:

http://www.quinapalus.com/picsi.html

HenrikOlsson
- 12th January 2015, 11:07
Out of curiosity, how many channels do you need?
8 channels for 4 * 2 note polyphony? Highest/lowest output frequency?
What frequency resolution would be considered good enough?

CuriousOne
- 12th January 2015, 17:14
Actually, capabilities of AY-3-8910 will be enough (3 channels). Since I want to incorporate famous NES game tunes into my project as easter egg. If it was dedicated project, I can use that chip, which I have used on ZX Spectrum quite long time ago, but I'm space and hardware resources limited, so this is why I'm asking for software solution.

HenrikOlsson
- 13th January 2015, 07:05
Hi,
I fooled around with this a bit yesterday. I've got a software solution for generating three tones but there is (and won't be) any noise, mixer, envelope, shape and whatever else the AY-3-8910 can do - just three tone generators. I have no idea if it'll work in practice or how good it'll "sound" but scope and frequency counter shows correct values for, at this point, three octaves.

With 3 channels it will NOT work at 4MHz, it MIGHT just work at 8MHz but there won't be much left do anything else. I'm currently running it on a 18F25K20 @64MHz so I need to breadboard something with a less capable chip and see what gives. Obviously the lower the maximum output frequency needs to be the more can be achieved with a low clock frequency so I'll ask again: What's the maximum output frequency you NEED?

Is the 12F683 the desried target chip and will you able to run it with external clock (to get 16MHz or 20MHz)? As it's written it relies on the prescense of a TMR2 module and uses interrupts at the ASM level, though the actual ISR is written in PBP with manual system register save/restore.

Are you aiming to do other things as well with this same chip?

It's not ready for public viewing yet, I'll post it when it is (or not if the answers to the above questions shows it's a dead end....)

/Henrik.

CuriousOne
- 13th January 2015, 12:54
Here is the sample (intro music)

https://www.youtube.com/watch?v=KHxD5-ZcOIA

You can see, it uses only 3 channels, no SFX or sophisticated envelope/shaping.

For the hardware, main MCU is 16F877A @ 20mhz. I want code to run on it, or if it'll be better to have separate chip, I have space for SOIC-8 case, this is why I said 12F683, but it can be say 12F1840 or whatsoever (no space for extra xtal, but I can use CLKOOUT from main chip).

HenrikOlsson
- 13th January 2015, 13:14
Hi,

> You can see, it uses only 3 channels, no SFX or sophisticated envelope/shaping
No, *I* can definitely not see (or hear) it. I know nothing about composing music of any kind so I'll take your word for it ;-)

Are you using interrupt on the main CPU already and if so is it DT-INTS?

The code should run on a 16F877 at 20MHz but it'll absorb a fair bit of the available CPU cycles meaning everthing else will run slow(ish). I'll get some data on it when I get a chance to work on it again. The 12F1840 has an internal 32MHz oscillator - that should work pretty well.

/Henrik.

Ioannis
- 13th January 2015, 13:51
16F877 made that video game??

Ioannis

CuriousOne
- 13th January 2015, 13:57
No, that video game runs on 6502 or similar CPU. It is possible to emulate NES using PIC, using various models, check this link as example:
https://www.youtube.com/watch?v=ZiRC5mj209s

For the my intended music playback, 877A uses DT-INTs, and for the easter egg moment, which will be achieved when user presses certain combo of keys, ther will be a small animation on 1602 display, and music should be playing, MCU won't be doing anything sophisticated that time.

HenrikOlsson
- 14th January 2015, 21:09
Hi,
So, I've played around some more.....
It won't run at anything below 16MHz. Even at 16MHz the interrupt routine, executing at 10kHz cosumes 70% of the available CPU cycles.
I've only tried it on an 18F25K20 @64MHz, you try it on a 16F or 12F1840 and see if it works.

You can not cut'n'paste this into a program using DT-Ints. Try it stand-alone first and we'll see about DT-ints later - if needed.

/Henrik.



'************************************************* ***************
'* Name : 3xSound generator.pbp *
'* Author : Henrik Olsson *
'* Notice : Written by Henrik Olsson 2015 *
'* : Free software, use as you wish. *
'* Date : 2015-01-14 *
'* Version : 1.0 *
'* Notes : Written in response to a thread on the PBP forum: *
'* : www.picbasic.co.uk/forum/showthread.php?t=19684 *
'* *
'* : Tones are generated using the DDS tecnique with a *
'* simple 16bit accumulator to which a value gets *
'* added once every interrupt (100us). When the *
'* accumulator overflows the output is toggled. *
'* Three generators are incorporated since that was *
'* the request. More could be added if the PIC is *
'* clocked fast enough. With three generators 16MHz *
'* is the lowest you want to use. The interrupts *
'* then uses ~70% of the available CPU cycles when *
'* three tones are generated. *
'* *
'* Version history: *
'* v1.0 2015-01-14 - Initial version *
'* *
'************************************************* ***************

' CONFIG's, TRIS's, ANSEL's CMCON's and anything device specific is not shown

DEFINE OSC 64
DEFINE INTHAND Generate ' We're treating the interrupt as an ASM routine (see notes!)

'-------------------------------------------------------------------------------------------
' These variables and alises are needed by the sound generator and needs to be
' accessed by the user.
Channel_1 VAR PortC.0 ' Output for sound channel 1
Channel_2 VAR PortC.1 ' Output for sound channel 2
Channel_3 VAR PortC.2 ' Output for sound channel 3

TMR2IF VAR PIR1.1 ' Alias to TMR2 Interrupt Request Flag - verify against datasheet.

Output_1 VAR WORD ' Desired output frequency, Channel 1, 13.107 units per Hz
Output_2 VAR WORD ' Desired output frequency, Channel 2, 13.107 units per Hz
Output_3 VAR WORD ' Desired output frequency, Channel 3, 13.107 units per Hz

Duration_1 VAR WORD ' Duration of tone, Channel 1, 100us units.
Duration_2 VAR WORD ' Duration of tone, Channel 2, 100us units.
Duration_3 VAR WORD ' Duration of tone, Channel 3, 100us units.

'-------------------------------------------------------------------------------------------
' These are variables used by the interrupt service routine.
' No user servicable parts inside......
R0_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR
R1_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR
R4_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR

Accumulator_1 VAR WORD ' DDS accumulator for sound generator 1
Accumulator_2 VAR WORD ' DDS accumulator for sound generator 2
Accumulator_3 VAR WORD ' DDS accumulator for sound generator 3

old_1 VAR WORD ' Used to detect overflow of accumulator 1
old_2 VAR WORD ' Used to detect overflow of accumulator 2
old_3 VAR WORD ' Used to detect overflow of accumulator 3
'--------------------------------------------------------------------------------------------

' We want 10kHz interrupt rate, that's 100us between interrupts.
' The interrupt routine needs around ~280 instruction cycles when
' outputting on three channels.
'
' At 16MHz that would be 400 instructions - 70% used by the generator.
' At 20MHz that would be 500 instructions - 56% used by the generator
' At 40MHz that would be 1000 instructions - 28% used by the generator
' At 64MHz that would be 1600 instructions - 17.5% used by the generator
'
' T2CON and PR2 needs to be setup so that an interrupt is triggered every 100us
' Use one of the follwing:
' PR2 = 99 : T2CON = %00000110 ' For 64MHz - 1:16 prescaler
' PR2 = 49 : T2CON = %00000110 ' For 32MHz - 1:16 prescaler
' PR2 = 124 : T2CON = %00000101 ' For 20MHz - 1:4 prescaler
' PR2 = 99 : T2CON = %00000101 ' For 16MHz - 1:4 prescaler

PR2 = 99 : T2CON = %00000110 'TMR2 on, postscaler 1:1, prescaler 1:4

IPR1.1 = 1 ' TMR2 high priority
PIE1.1 = 1 ' TMR2 IE
INTCON.6 = 1 ' PIE
INTCON.7 = 1 ' GIE


Main:
' All three notes will play simultanously for the specified duration.
' The sound is generated in the background so the PAUSE 1000 will
' execute at the same time as the notes are played. Remember though that
' the interrupt "steals" time so the PAUSE isn't correct. The slower the
' PIC clock is the more inacurate it gets.

Output_1 = 857 : Duration_1 = 500 'Play C2 (65.4Hz) for 50ms
Output_2 = 5767 : Duration_2 = 2500 'Play A4 (440.0Hz)for 250ms
Output_3 = 25893 : Duration_3 = 1000 'Play B6 (1975.5Hz) for 100ms

Pause 1000

Goto Main


'-------------------------------------------------------------------------------
' Actual interrupt routine here. Please note that this is written in PBP but
' the interrupt is handled as if it were a ASM interrupt. As far as I can see
' it uses PBP system variables R0, R1, R4 so I'm saving/restoring those.
' If ANY code gets added here then the ASM-listning needs to be checked to
' see of the added PBP code uses any more system variables and if so
' those needs to saved/restored as well.
' When all three channels produces output it needs ~280 instructions cycles.
@ Generate:

@ MOVE?WW R0, _R0_SHADOW ; Save PBP system variable R0
@ MOVE?WW R1, _R1_SHADOW ; Save PBP system variable R1
@ MOVE?WW R4, _R4_SHADOW ; Save PBP system variable R4
TMR2IF = 0

IF Duration_1 > 0 THEN
Accumulator_1 = Accumulator_1 + Output_1
If Accumulator_1 < old_1 THEN Toggle Channel_1
old_1 = Accumulator_1
Duration_1 = Duration_1 - 1
ELSE
Channel_1 = 0
ENDIF

IF Duration_2 > 0 THEN
Accumulator_2 = Accumulator_2 + Output_2
If Accumulator_2 < old_2 THEN Toggle Channel_2
old_2 = Accumulator_2
Duration_2 = Duration_2 - 1
ELSE
Channel_2 = 0
ENDIF

If Duration_3 > 0 THEN
Accumulator_3 = Accumulator_3 + Output_3
If Accumulator_3 < old_3 THEN Toggle Channel_3
old_3 = Accumulator_3
Duration_3 = Duration_3 - 1
ELSE
Channel_3 = 0
ENDIF


@ MOVE?WW _R0_SHADOW, R0 ; Restore PBP system variable R0
@ MOVE?WW _R1_SHADOW, R1 ; Restore PBP system variable R1
@ MOVE?WW _R4_SHADOW, R4 ; Restore PBP system variable R4

@ retfie FAST
'-------------------------------------------------------------------------------
END

CuriousOne
- 15th January 2015, 03:38
WOW, so fast!

It's my fault, I forgot to mention, we only need high frequencies for SFX synthesis, for music playback, 5 octave range is enough, which means roughly 440*5=2.2khz

HenrikOlsson
- 15th January 2015, 06:21
Hi,
2.2kHz (Output_x = 28835) should work. The higher you go the more jittery the output becomes.

If you want to calculate the value to put in the Output_x variables at runtime (instead of using a lookup table or whatever) you can do it with Output_x = ( Frequency + ( Frequency ** 20353 ) ) where Frequency is a WORD containing the desired output frequency * 10, (4400 = 440.0Hz)

It's not perfect but may be good enough.

Let me know if you get around to trying it.

/Henrik.

CuriousOne
- 15th January 2015, 06:48
What happens if I run this code say at 4mhz 16F870 ? there will be no output, frequency wont match, or sound will be breaking up?

CuriousOne
- 15th January 2015, 07:30
on 16F876A, gives error during compile on this:

IPR1.1 = 1 ' TMR2 high priority

CuriousOne
- 15th January 2015, 07:44
Gives same error on 12F1840.

HenrikOlsson
- 15th January 2015, 07:59
Hi,

> What happens if I run this code say at 4mhz 16F870 ? there will be no output, frequency wont match, or sound will be breaking up?

There's not enough time to actually execute the interrupt service routine before the timer fires another interrupt. The CPU will spend all of its time in the ISR, no time left for you to set the desired frequencies etc and the output frequenices will be wrong and...... Simply - It just won't work. You need 16MHz.

> on 16F876A, gives error during compile on this:
> IPR1.1 = 1 ' TMR2 high priority

The 16F series doesn't have interrupt priorities, remove the line.

> Gives same error on 12F1840.

The 12F series doesn't have interrupt priorities, remove the line.

/Henrik.

CuriousOne
- 15th January 2015, 08:33
Still does not compile on 16F876A -

ASM ERROR:
Symbol not previously defined (wsave), (ssave), (psave).

Compile OK on 12F1840, but ASM warning - Found label after column 1. (Generate), Extraneous arguments on the line

CuriousOne
- 15th January 2015, 08:35
added this for 16F876A:



wsave VAR BYTE $20 SYSTEM
ssave VAR BYTE $22 SYSTEM
psave var byte $24 SYSTEM


Have no idea why, but no more errors in compile, will try runtime shortly.

CuriousOne
- 15th January 2015, 09:06
It works, sort of (20mhz crystal 16F876A).

If any channel duration has same value, these channels won't play.
Also, playback duration is different each time, it might play 4 or 5 times same duration, then 2 times shorter duration, then again normal.
It works properly only when value of output timings is first is the shortest, 2nd medium and 3rd - longest. If in reverse, it will only play last, short one.

HenrikOlsson
- 15th January 2015, 09:27
Hi,

> Still does not compile on 16F876A -
> ASM ERROR:
> Symbol not previously defined (wsave), (ssave), (psave).

Do you have DT-Ints in the program? I thought I said:

You can not cut'n'paste this into a program using DT-Ints. Try it stand-alone first and we'll see about DT-ints later - if needed.

> Compile OK on 12F1840, but ASM warning - Found label after column 1. (Generate), Extraneous arguments on the line
That's a warning, have you edited the source in any way? I don't get that here.....

> If any channel duration has same value, these channels won't play.
> Also, playback duration is different each time, it might play 4 or 5 times same duration, then 2 times shorter duration, then again normal.
> It works properly only when value of output timings is first is the shortest, 2nd medium and 3rd - longest. If in reverse, it will only play last, short one.

Are you running the program, by itself, on the 16F877 at 20MHz or are you, despite my warning, trying to run it together with the rest of your program AND DT-INTS?

/Henrik.

richard
- 15th January 2015, 10:04
any pic without auto context save will need the wsave psave vars added


this compiles ok for a 12f1822 watch the define OSC not sure how fast a 12f1822 is


'************************************************* ***************
'* Name : 3xSound generator.pbp *
'* Author : Henrik Olsson *
'* Notice : Written by Henrik Olsson 2015 *
'* : Free software, use as you wish. *
'* Date : 2015-01-14 *
'* Version : 1.0 *
'* Notes : Written in response to a thread on the PBP forum: *
'* : www.picbasic.co.uk/forum/showthread.php?t=19684 (http://www.picbasic.co.uk/forum/showthread.php?t=19684) *
'* *
'* : Tones are generated using the DDS tecnique with a *
'* simple 16bit accumulator to which a value gets *
'* added once every interrupt (100us). When the *
'* accumulator overflows the output is toggled. *
'* Three generators are incorporated since that was *
'* the request. More could be added if the PIC is *
'* clocked fast enough. With three generators 16MHz *
'* is the lowest you want to use. The interrupts *
'* then uses ~70% of the available CPU cycles when *
'* three tones are generated. *
'* *
'* Version history: *
'* v1.0 2015-01-14 - Initial version *
'* *
'************************************************* ***************
' CONFIG's, TRIS's, ANSEL's CMCON's and anything device specific is not shown
DEFINE OSC 20
DEFINE INTHAND _Generate ' We're treating the interrupt as an ASM routine (see notes!) did not like asm label not sure why
'-------------------------------------------------------------------------------------------
' These variables and alises are needed by the sound generator and needs to be
' accessed by the user.
Channel_1 VAR Porta.0 ' Output for sound channel 1
Channel_2 VAR Porta.1 ' Output for sound channel 2
Channel_3 VAR Porta.2 ' Output for sound channel 3
TMR2IF VAR PIR1.1 ' Alias to TMR2 Interrupt Request Flag - verify against datasheet.
Output_1 VAR WORD ' Desired output frequency, Channel 1, 13.107 units per Hz
Output_2 VAR WORD ' Desired output frequency, Channel 2, 13.107 units per Hz
Output_3 VAR WORD ' Desired output frequency, Channel 3, 13.107 units per Hz
Duration_1 VAR WORD ' Duration of tone, Channel 1, 100us units.
Duration_2 VAR WORD ' Duration of tone, Channel 2, 100us units.
Duration_3 VAR WORD ' Duration of tone, Channel 3, 100us units.
'-------------------------------------------------------------------------------------------
' These are variables used by the interrupt service routine.
' No user servicable parts inside......
R0_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR
R1_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR
R4_SHADOW VAR WORD ' Variable used for saving PBP system variables in the ISR
Accumulator_1 VAR WORD ' DDS accumulator for sound generator 1
Accumulator_2 VAR WORD ' DDS accumulator for sound generator 2
Accumulator_3 VAR WORD ' DDS accumulator for sound generator 3
old_1 VAR WORD ' Used to detect overflow of accumulator 1
old_2 VAR WORD ' Used to detect overflow of accumulator 2
old_3 VAR WORD ' Used to detect overflow of accumulator 3
'--------------------------------------------------------------------------------------------
' We want 10kHz interrupt rate, that's 100us between interrupts.
' The interrupt routine needs around ~280 instruction cycles when
' outputting on three channels.
'
' At 16MHz that would be 400 instructions - 70% used by the generator.
' At 20MHz that would be 500 instructions - 56% used by the generator
' At 40MHz that would be 1000 instructions - 28% used by the generator
' At 64MHz that would be 1600 instructions - 17.5% used by the generator
'
' T2CON and PR2 needs to be setup so that an interrupt is triggered every 100us
' Use one of the follwing:
' PR2 = 99 : T2CON = %00000110 ' For 64MHz - 1:16 prescaler
' PR2 = 49 : T2CON = %00000110 ' For 32MHz - 1:16 prescaler
' PR2 = 124 : T2CON = %00000101 ' For 20MHz - 1:4 prescaler
' PR2 = 99 : T2CON = %00000101 ' For 16MHz - 1:4 prescaler

PR2 = 99 : T2CON = %00000110 'TMR2 on, postscaler 1:1, prescaler 1:4
'IPR1.1 = 1 ' TMR2 high priority
PIE1.1 = 1 ' TMR2 IE
INTCON.6 = 1 ' PIE
INTCON.7 = 1 ' GIE

Main:
' All three notes will play simultanously for the specified duration.
' The sound is generated in the background so the PAUSE 1000 will
' execute at the same time as the notes are played. Remember though that
' the interrupt "steals" time so the PAUSE isn't correct. The slower the
' PIC clock is the more inacurate it gets.
Output_1 = 857 : Duration_1 = 500 'Play C2 (65.4Hz) for 50ms
Output_2 = 5767 : Duration_2 = 2500 'Play A4 (440.0Hz)for 250ms
Output_3 = 25893 : Duration_3 = 1000 'Play B6 (1975.5Hz) for 100ms
Pause 1000
Goto Main

'-------------------------------------------------------------------------------
' Actual interrupt routine here. Please note that this is written in PBP but
' the interrupt is handled as if it were a ASM interrupt. As far as I can see
' it uses PBP system variables R0, R1, R4 so I'm saving/restoring those.
' If ANY code gets added here then the ASM-listning needs to be checked to
' see of the added PBP code uses any more system variables and if so
' those needs to saved/restored as well.
' When all three channels produces output it needs ~280 instructions cycles.
Generate : made this a pbp label
@ MOVE?WW R0, _R0_SHADOW ; Save PBP system variable R0
@ MOVE?WW R1, _R1_SHADOW ; Save PBP system variable R1
@ MOVE?WW R4, _R4_SHADOW ; Save PBP system variable R4
TMR2IF = 0
IF Duration_1 > 0 THEN
Accumulator_1 = Accumulator_1 + Output_1
If Accumulator_1 < old_1 THEN Toggle Channel_1
old_1 = Accumulator_1
Duration_1 = Duration_1 - 1
ELSE
Channel_1 = 0
ENDIF

IF Duration_2 > 0 THEN
Accumulator_2 = Accumulator_2 + Output_2
If Accumulator_2 < old_2 THEN Toggle Channel_2
old_2 = Accumulator_2
Duration_2 = Duration_2 - 1
ELSE
Channel_2 = 0
ENDIF

If Duration_3 > 0 THEN
Accumulator_3 = Accumulator_3 + Output_3
If Accumulator_3 < old_3 THEN Toggle Channel_3
old_3 = Accumulator_3
Duration_3 = Duration_3 - 1
ELSE
Channel_3 = 0
ENDIF

@ MOVE?WW _R0_SHADOW, R0 ; Restore PBP system variable R0
@ MOVE?WW _R1_SHADOW, R1 ; Restore PBP system variable R1
@ MOVE?WW _R4_SHADOW, R4 ; Restore PBP system variable R4

@ retfie ; ' no fast

HenrikOlsson
- 15th January 2015, 10:24
Thanks Richard!
Didn't think about the lack of auto context save on the 16F parts, thanks for picking that up!

Yes, the 12F1822 can run at up to 32MHz from its internal oscillator and it has the auto context save - it would be a good choice for this, as said before.

CuriousOne,
Please try Richards edited version on your 12F1822 and see if it works.

/Henrik.

richard
- 15th January 2015, 10:36
you might save a few cycles if you clear the tris bit for the outputs and


replace the If Accumulator_x < old_x THEN Toggle Channel_x lines

with If Accumulator_x < old_x THEN Channel_x=! Channel_x

CuriousOne
- 15th January 2015, 10:36
I'm running it separately, without any interrupts or code involved.

richard
- 15th January 2015, 10:42
the label problem is resolved with

@Generate
instead of
@ Generate

richard
- 15th January 2015, 10:45
wsave psave etc can't just go anywhere

try this


wsave VAR BYTE $70 SYSTEM ;wsave in access RAM
ssave VAR BYTE BANK0 SYSTEM
psave VAR BYTE BANK0 SYSTEM


not sure when to use wsave VAR BYTE $20 SYSTEM

CuriousOne
- 15th January 2015, 12:48
OK, will try later, my programmer engulfed in smokes right now :)

longpole001
- 24th January 2015, 23:08
here is somthing i was impressed with for sound from apic
http://www.pic24.ru/doku.php/en/osa/articles/pk2_osa_piano

longpole001
- 24th January 2015, 23:58
also has interesting approch to matrix touch sensor array , and 8ch polymorphic generation using 1 pwm pin

Ioannis
- 26th January 2015, 07:42
I saw this before and was very impressed by the speed of touch sensors, sound quality and simplicity of the design. Great job.

Ioannis