It is currently Mon Apr 23, 2018 3:42 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 97 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7
Author Message
PostPosted: Tue Oct 03, 2017 11:03 pm 
Offline
User avatar

Joined: Mon Apr 04, 2011 11:49 am
Posts: 2062
Location: WhereverIparkIt, USA
Well it's happened again, get around to writing some code and taking a closer look at the STM8 register settings, and I found a little gem.

TIM2 is the mid grade counter on chip I've dedicated to the PWM DAC. It's only capable of up counting, and thus has no center aligned PWM mode of operation. HOWEVER there is an output mode that toggles the output pin on timer compare match. Taking advantage of this, one can effectively create a center aligned PWM if you're willing to dedicate the CPU resources to update the compare value on each timer overflow. I'm not yet sure I've got the resources to pull this off in my case, we'll see.

To make this work all that needs to be done is invert the DAC value every other output. We can also take advantage of Tepples tip to keep from loosing a bit of resolution, it's best of both worlds with this trick if there's CPU resources to spare.

Here's how I'm thinking this would work:
-Assuming 16Mhz counter clock, 31Khz PWM freq, counter top value of 255 (0xFF), normally give 8bit DAC, but can gain a bit back for 9bits if down doesn't have to equal up count.

Start with PWM output clear. Say the desired output value for this cycle is 100.5

1)First update cycle is "odd" operation and thus going to simulate down counting. By convention let's round down on odd/down cycles, so this half's output is 100. Being an odd cycle we subtract 100 from the top value 255. We place this difference of 155 in the compare register. When reached the output PWM pin toggles high.

2)Next output cycle occurs, this one is "even" normal up counting. Round up this time from 100.5 to 101. The 101 value is simply placed in the compare register. When reached the output PWM pin toggles low.

3) Calculate next DAC output value and go to step 1.

While this idea works, the added interrupt for step 2 will be costly for the STM8. Interrupts cost a whopping 20 cycles (9 pushes, 2 jump isr, 9 pops). This scenario requires two interrupts per 512 clock update cycle. That's 4% CPU resources for the added interrupt entry/exit, prob need another 5-10 cycles to support the added complexity running each isr, so that's another ~4%, for a total CPU resource cost of 8%. Doesn't seem worthwhile at this point anyway when we've got better things to do with that CPU time. So while this whole trick is viable, but I've now sufficiently talked myself out of it...

I sure wish all those excessive register pushes for STM8 ISRs wasn't there. Much more convenient how the 6502 only pushes PC & SR.. Leave it to the ISR to decide what registers are worth preserving! Worst part about it is, the built in pushes aren't any faster than manual pushing; all they're saving is code bytes.

_________________
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers


Top
 Profile  
 
PostPosted: Wed Oct 04, 2017 11:26 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7013
Location: Seattle
One little caveat about the "just use a count-up / count-down PWM and alternate direction every reload" — it effectively halves your sample rate (and adds one to the bit depth), producing modulation noise at IRQ frequency/2.

15.5kHz is still high enough that it's likely not an issue, but it's worth keeping in mind.


Top
 Profile  
 
PostPosted: Wed Oct 04, 2017 11:56 am 
Offline
User avatar

Joined: Mon Apr 04, 2011 11:49 am
Posts: 2062
Location: WhereverIparkIt, USA
lidnariq wrote:
One little caveat about the "just use a count-up / count-down PWM and alternate direction every reload" — it effectively halves your sample rate (and adds one to the bit depth), producing modulation noise at IRQ frequency/2.


Yeah my initial thought was to run the synth engine on each count "direction" to keep from changing the sample rate. But that doubles the synth computation load in order to keep the same PWM frequency. With limited timer clock speed, and limited CPU resources, there's no way to get around some sort of trade off when going from fast/edge to center/phase correct. And with your conclusion of giving up 1 bit of resolution not being worth gaining center aligned, I question if center aligned is ever worthwhile in a system operating near it's constraints.

_________________
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers


Top
 Profile  
 
PostPosted: Mon Oct 09, 2017 9:47 pm 
Offline
User avatar

Joined: Mon Apr 04, 2011 11:49 am
Posts: 2062
Location: WhereverIparkIt, USA
Quick little update, testing out the PWM DAC with a simple middle C square wave. Current PWM DAC is the standard 3.9k 4.7nF (8.7Khz cutoff) low pass filter fed directly to EXP6. Then fed through the 'standard' 47k EXP audio resistor I was able to achieve a volume comparable to one of the 2a03's squares at full volume. Things went according to my plan here with a DAC setting of ~12% the CICOp square was audibly similar to the 2a03 square in volume and timbre. I haven't came up with a means to objectively compare the two, but using my ears alone the CICOp may have sounded a little "warmer" but honestly I could be mistaking that based on slight difference in volume. In any event I'm happy with the preliminary performance of this simple setup!

I took a handful of different scope measurements, still blows me away that the PWM DAC sounds as good as it does despite how it looks! [EDIT: all measurements taken with 10x probe]

Realizing a limitation of running at PWM frequency of 31Khz is the min period resolution of 32usec which I assume will prove troublesome for keeping higher pitched notes in tune.. I may be able to pull off 62Khz, but I'm wondering if this could be made up for by counting fractional steps and then rounding each period. Where the the average of something like 4 cycles would be in tune effectively providing 8usec period resolution. Have a feeling a hack like that has some (audible) drawback but I don't really know..


Attachments:
File comment: 31Khz PWM noise alive and well at output level ~3.1vdc
image.jpg
image.jpg [ 1.42 MiB | Viewed 637 times ]
File comment: Middle C, measured on main board 20k mixing resistor (between 47k exp resistor)
image.jpg
image.jpg [ 1.44 MiB | Viewed 637 times ]
File comment: Middle C, output of PWM DAC
image.jpg
image.jpg [ 1.39 MiB | Viewed 637 times ]
File comment: Step response from 5v->0v, then ramp to 5v in one step increments.
image.jpg
image.jpg [ 1.39 MiB | Viewed 637 times ]

_________________
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers


Last edited by infiniteneslives on Tue Oct 10, 2017 9:14 am, edited 1 time in total.
Top
 Profile  
 
PostPosted: Mon Oct 09, 2017 9:58 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7013
Location: Seattle
infiniteneslives wrote:
Realizing a limitation of running at PWM frequency of 31Khz is the min period resolution of 32usec which I assume will prove troublesome for keeping higher pitched notes in tune.
It isn't necessary to have pitches be integer divisors of your sample rate.

It's true that square waves (or anything else with more higher frequency content) will start having audible aliasing artifacts if you just use nearest-neighbor=sample-and-hold resampling, but that can be fixed or worked around in a variety of ways.

Quote:
I'm wondering if this could be made up for by counting fractional steps and then rounding each period. Where the the average of something like 4 cycles would be in tune effectively providing 8usec period resolution. Have a feeling a hack like that has some (audible) drawback but I don't really know.
That's actually literally how the Namco 163 works. The waveform position there is 8.16 fixed point (and the pitch is 2.16 fixed point). The SNES does something similar (pitch is 2.12 fixed point), but it adds an interpolator ("Gaussian") to reduce aliasing noise (and everything else high frequency, oops)


Top
 Profile  
 
PostPosted: Thu Oct 12, 2017 1:18 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6218
Location: Canada
Yeah, with accumulator based tones (e.g. N163, FDS, SID) it's not a divider of the clock frequency, and your low pitch precision ends up at low frequencies instead of high.

It's the inverse of the clock divider approach (e.g. 2A03, VRC6, AY).

I think the main difference is that the divider gets a lot more range with less bits in the register, and only has to increment instead of doing a full add. (Also at 31 kHz you'll have audible aliasing, but probably acceptable. No worse than N163 in 4 channel mode.)


Top
 Profile  
 
PostPosted: Sat Mar 17, 2018 3:47 pm 
Offline
User avatar

Joined: Mon Apr 04, 2011 11:49 am
Posts: 2062
Location: WhereverIparkIt, USA
Wanted to take a min and post a bit of an update on where I'm at with this project so far.

Firstly in STM8 news, ST bested themselves with the addition of a soic-8 package version with the STM8S001 (datasheet). It's the same silicon as the STM8S003, but only 5 GPIO. The pinout is rather interesting, it completely cuts out the /RESET pin, and of the 5GPIO many of the pins have multiple GPIO bonded to the same package pin. So there's a decent number of peripherals still available despite the low pin count, but you have to be cautious to not enable more than one driver for a given package pin.

Anyway, the soic-8 package gives up most of it's pins and now beats out the stm8s003 in price, but it's a pretty minor difference. The soic-8 package allowed for easier migration for some of my designs from attiny13 as the footprint didn't have to change. I included it in my latest discrete mapper board design and have started using it in production. None of that really has much to do with this project though. At most with the SOIC-8 package only ~2 i/o pins are left over for added features which isn't enough to do anything on the level of what the CICOprocessor is targetting. I'm using those 2 spare pins for mirroring control with a MUX, and PRG-ROM /WE control to separate mapper writes from PRG-ROM writes without an EXP0 pin which will be extra helpful for a 60pin famicom version I'm hoping to wrap up soon.

I successfully converted my NES CIC design over to the TIM1 counter method of keeping track of CIC cycles as I had already done with SNES. I also successfully combined the CIC RESET pin with KEY DOUT. It turned out that it works better to combine RESET with the KEY's data output instead of the LOCK's output. Reason being is that wire ORing the pins results in a lower Voh of the original CIC in the console. In my experimentation, this reduction is more significant with the SNES CIC than the NES for whatever reason. The reduction in Voh can be enough to get too close to the Vih of the cartridge CIC for comfort. The mcu's CMOS driver has no problem driving close to the full 5v on two wire ORed pins of the console though. The only important inputs for the cartridge CIC are the RESET pulse and stream ID on LOCK DOUT. So those come in on separate mcu pins, but then the mcu drives it's Dout on the combined RESET/KEY_DOUT pin.

So that's all good news for the CICOp's plan to only have 2 GPIO used for CIC RESET, KEY_IN, & KEY_OUT. Next step is to migrate CIC timing from using TIM1 clocked externally from CIC_CLK, to TIM4 being clocked asynchronously by the 16Mhz HSI. Getting my drift calibration factor working will be the biggest challenge with this. But I think I can pull it off leaving TIM1 available for scanline/CPU cycle counting.

The fact the stm8 core is always running off the internal HSI greatly simplifies communicating with it when it's plugged into something like my programmer. I've been able to implement some less impressive features I had planned. Basically the cartridge's circuit board is now serialized via the CIC with some reasonable security. I have the STM8's read out protection enabled so an external programmer can't access flash, eeprom, nor CPU registers. But it does still have access to RAM, which my programmer is able to read out via the SWIM interface. Currently when the STM8 boots up I have it copy any data that may be of interest to the bottom of the stack. So it doesn't really have dedicated RAM allocated to it, and it'll be visible so long as the stack hasn't been heavily used since boot. So I've got a string that's able to be read out by the programmer which includes things like the CIC build name and version, PCB's version, special text where I've placed things like "LizardV1" or "LizardV2" based on the homebrew game and it's build version. For a little extra flare, I've been able to put include a 96bit guaranteed unique ID number. I can't think of a great use for it, but if someone wanted to keep a registry of boards utilized for a limited edition to allow for later verification they could. I'm able to easily come up with a unique ID even though the STM8S001/3 doesn't have "96bit unique chip ID" advertised as a feature like the STM8S103. In the end the stm8s103 is the same silicon as stm8s001/3, so the unique chip ID (fablot, wafer number & X/Y location) info is all there, may as well do something potentially useful with it! :) Beyond that I do copy over a "copyright Infinite NES Lives LLC" string into RAM as well.

Coming up with detection algorithms for all the different boards I've made has always been a daunting task. So that feature is handy for the programmer to have a simple means of determining board & mapper info etc. The copyright message also provides a sizable string to read out and verify all is well with SWIM communications.

One other gotcha that I somehow didn't pick up until recently is that the "True open drain" GPIO pins lack a P driver completely. I had realized they didn't have pull-up resistors, but didn't realize they had no ability to drive the pin high until recently. So that limits what can be done with those pins a little, but shouldn't be too big of issue now that I'm aware of it.

Moving forward lidnariq has got me interested in the greenpak finally. Now that there's a tssop-20 package available which can also be reconfigured I'm starting to think the SLG46824 could make for a nice pairing with the CICOprocessor. I didn't have much planned for the I2C pins on the CICOp so giving it the ability to configure and possibly communicate with the mapper is an interesting thought. I still haven't fully wrapped my head around the greenpak's abilities, nor am I certain of it's costs. Looks like the price may be comparable to amount of logic needed for UNROM512 which means it may be within reach with this project's minimal cost goals. I messaged Dialog for a quote and will probably pick up a devkit to tinker around with soon.

_________________
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 97 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group