Jump to content
IGNORED

PWM using joystick port


mytek

Recommended Posts

Does anyone know where I can find a PWM routine that utilizes a joystick pin as an output. Resolution should be 8-bits (1 byte register). Preferably a machine language routine that runs in the background, and using Basic to change PWM register value.

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

Pretty sure the GTIA tunes use PWM. In theory they could be modified to output to a joystick bit instead.

 

Highly unlikely it's anywhere near 8 bits. Doing PWM on Atari relies on a software delay, part of the problem is you have refresh cycle steals which can't be avoided even with screen disabled to get rid of those cycles lost.

 

Problem 2 is for PWM to be usable you need to do it at a reasonably high frequency to begin with. 2 scanlines per sample = a little over 8 KHz but that equates to only 228 machine cycles which is almost 8 bits worth of resolution.

Link to comment
Share on other sites

Pretty sure the GTIA tunes use PWM. In theory they could be modified to output to a joystick bit instead.

 

Highly unlikely it's anywhere near 8 bits. Doing PWM on Atari relies on a software delay, part of the problem is you have refresh cycle steals which can't be avoided even with screen disabled to get rid of those cycles lost.

 

Problem 2 is for PWM to be usable you need to do it at a reasonably high frequency to begin with. 2 scanlines per sample = a little over 8 KHz but that equates to only 228 machine cycles which is almost 8 bits worth of resolution.

 

Awww good point about the cycle stealing :ponder: I totally forgot about that. For my application, high frequency is not a requirement (I'll be creating an analog output with an RC network). I have a good amount of time, so even if heavy filtering needs to be used that is okay. But even so, it still looks problematic considering the display interrupts (I can't turn off the display). So here is what I need this for... I wish to feed an analog signal to a DAC on a PC running a DasyLab program, and have it display positional information in this program. The resolution of this required data needs to show approximately 200 positions and it does not have to be absolutely exact. So that is why I was thinking of having an 8-bit PWM based signal which gives me 255 data points to work with. I also only have one free output bit from a joystick port to use. And last but not least I have plenty of spare analog inputs on the DAC I will be utilizing, hence the thought behind converting the PWM signal into an analog one.

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

Use a resistor ladder on a number of digital pins (aka a poor man's DAC). If you throw 2 joystick ports at it, you'll have 8 bits.

 

Easily handled with BASIC, and no worries about lost cycles.

 

[edit - Ah, missed the part about there only being 1 free pin. That is a hard one. With variable length bits and no clock line, anything digital in between is problematic.]

Link to comment
Share on other sites

 

I also only have one free output bit from a joystick port to use. And last but not least I have plenty of spare analog inputs on the DAC I will be utilizing, hence the thought behind converting the PWM signal into an analog one.

 

- Michael

Wow that is tough!

 

I was thinking shift register like a 74ls164 until I got to that part. Under the constraints you have, ~free running counter/timer with R2R on the output. J/S pin works as an enable pin and you adjust the clock frequency such that the refresh cycles that Rybags mentions become insignificant. There would still be some noise as the counter does its thing w/o some other circuitry to latch the output. Gets a little complicated like add a one shot 555 on the same J/S pin that waits for the longest theoretical count, then latches the output to an 8 bit latch with the R2R ladder on it. Some smart guy could probably do it with a single piece of programmable logic but my skills are weak. :)

Link to comment
Share on other sites

Yep you guys zeroed in on my problem... only 1 output bit available. This is why I was thinking PWM-to-Analog since a lot of info can be easily conveyed, but no synchronization required on the other end like what would be required if trying to bit-bang a serial transmission. I'm also trying to keep the hardware requirements to a minimum. But hey thanks for the creative ideas thus far ;-) .

 

- Michael

Link to comment
Share on other sites

Hi!

 

Yep you guys zeroed in on my problem... only 1 output bit available. This is why I was thinking PWM-to-Analog since a lot of info can be easily conveyed, but no synchronization required on the other end like what would be required if trying to bit-bang a serial transmission. I'm also trying to keep the hardware requirements to a minimum. But hey thanks for the creative ideas thus far ;-) .

 

- Michael

One possibility is using a combination of VBI (to set PORTA bit N to 0) and DLI (to set PORTA bit N to 1), timed so that the correct duty-cycle is generated.

 

The attached source (and MADS compiled binary) illustrates this, by setting/resetting PORTA bit 0.

 

From BASIC, you must load the routine first (in TBXL you can use BLOAD "D:PWM.OBX"), then you call "A=USR(1536)" to init the tables, and afterwards, simply "A=USR(1536,VAL)" to set the duty-cycle to VAL. Note that there are a minimum value possible for VAL about 15 (because the VBI timing) and a maximum value of 240 (because then you overlap the DLI with the VBI locking-up the Atari).

 

On init, the program reads the current display-list to get the addresses of the best instructions to add the DLI given each PWM value, and stores those addresses in a table. Afterwards, the display-list is modified adding a DLI at the proper location.

 

Untested, because I'm away from my Atari now, seems to work in emulators.

pwm.asm

PWM.OBX

  • Like 2
Link to comment
Share on other sites

Hi!

 

 

One possibility is using a combination of VBI (to set PORTA bit N to 0) and DLI (to set PORTA bit N to 1), timed so that the correct duty-cycle is generated.

 

The attached source (and MADS compiled binary) illustrates this, by setting/resetting PORTA bit 0.

 

From BASIC, you must load the routine first (in TBXL you can use BLOAD "D:PWM.OBX"), then you call "A=USR(1536)" to init the tables, and afterwards, simply "A=USR(1536,VAL)" to set the duty-cycle to VAL. Note that there are a minimum value possible for VAL about 15 (because the VBI timing) and a maximum value of 240 (because then you overlap the DLI with the VBI locking-up the Atari).

 

On init, the program reads the current display-list to get the addresses of the best instructions to add the DLI given each PWM value, and stores those addresses in a table. Afterwards, the display-list is modified adding a DLI at the proper location.

 

Untested, because I'm away from my Atari now, seems to work in emulators.

 

Ok I'm working under constrained memory still on my SIDE2 no/extended RAM 1200XL, so I loaded PWM.OBX from SDX, jumped into BASIC++ and was able to get it to work. Although first I had to set-up the port as an output. And then still no action until I got up to a value of 25, at which point the PWM signal jumped to life on my scope. Subsequently substituting new values worked over the entire range from 15-240 as you specified. However an interesting thing occurs when I have this running in a Basic program. On the first run all is well. Hit break to stop my program -- and the system usually locks up requiring powering down to get it working again. All my program does is the following (pseudo code)...

 

  1. Set PORTA as all outputs
  2. Initialize PWM code loaded in memory -- A=USR(1536)
  3. Set to 25 -- A=USR(1536,25)
  4. Open channel to keyboard -- OPEN #1,4,0,"K:"
  5. Begin Loop -- Get #1,KEY
  6. If KEY=Up and NUM<240 then NUM=NUM+1:A=USR(1536,NUM):goto 5
  7. If KEY=DOWN and NUM>15 then NUM=NUM-1:A=USR(1536,NUM):goto 5
  8. goto 5

 

I don't have enough memory to run this with TB using the SIDE2, so I'll have to try it later with the cart removed. Just wondering what the conflict is :?

 

But other than that glitch, it works beautifully!! Thanks a bunch for writing this :)

 

- Michael

 

EDIT: Just tested it without the SIDE2. Booted a DOS 2.5 image with Atari Basic rev C and BASIC++ on it. Same results with BASIC++, however running in Atari Basic immediately goes to a black screen and hangs.

Edited by mytekcontrols
  • Like 1
Link to comment
Share on other sites

3. Set NUM to 25 -- NUM=25 : do what you want following such as A=USR(1536,25)

 

I don't mind looking like the fool here with my mediocre BASIC talents, but the only variable I know of that absolutely doesn't need to be set before use is A=USR call. You have to DIM a string, you have to set variables. Other BASIC actually have a SET operative and require it's use religiously, Atari notably doesn't and can fly without - sometimes. Ok, most times then, but maybe this is the very sometime it doesn't fly so good?

 

I assume here that NUM<240 is the hang up with previously unused NUM variable, in 'normal' use it would have an unused base value of 1 but here it's being put to use in a 'complexed' logical compare WITH the first use and those two functions might not like being so close together inside BASIC P code. SETting it first avoids having to crawl back out of an IF/AND situation to find a value for NUM that really doesn't yet exist. And it may be that the IF/AND fails if we then have to 'give' the default value for NUM.

Link to comment
Share on other sites

Hi!,

 

Ok I'm working under constrained memory still on my SIDE2 no/extended RAM 1200XL, so I loaded PWM.OBX from SDX, jumped into BASIC++ and was able to get it to work. Although first I had to set-up the port as an output. And then still no action until I got up to a value of 25, at which point the PWM signal jumped to life on my scope. Subsequently substituting new values worked over the entire range from 15-240 as you specified. However an interesting thing occurs when I have this running in a Basic program. On the first run all is well. Hit break to stop my program -- and the system usually locks up requiring powering down to get it working again. All my program does is the following (pseudo code)...

  • Set PORTA as all outputs
  • Initialize PWM code loaded in memory -- A=USR(1536)
  • Set to 25 -- A=USR(1536,25)
  • Open channel to keyboard -- OPEN #1,4,0,"K:"
  • Begin Loop -- Get #1,KEY
  • If KEY=Up and NUM<240 then NUM=NUM+1:A=USR(1536,NUM):goto 5
  • If KEY=DOWN and NUM>15 then NUM=NUM-1:A=USR(1536,NUM):goto 5
  • goto 5
I don't have enough memory to run this with TB using the SIDE2, so I'll have to try it later with the cart removed. Just wondering what the conflict is :?

 

But other than that glitch, it works beautifully!! Thanks a bunch for writing this :)

 

- Michael

 

EDIT: Just tested it without the SIDE2. Booted a DOS 2.5 image with Atari Basic rev C and BASIC++ on it. Same results with BASIC++, however running in Atari Basic immediately goes to a black screen and hangs.

 

 

Well, the program has one *big* bug, it uses locations from $600 (1536) up to $71C (1820), but using BASIC + DOS, only locations from $600 to $6FF are available to ML programs...

 

One option is assembly to another location, attached is a version assembled at $7F00 (32512), this is a test program:

100 REM Load the assembly program
110 REM in TurboBasic simply use BLOAD "D:PWM.OBX"
120 OPEN #1, 4, 0, "D:PWM.OBX"
130 GOSUB 250: GOSUB 250: SETPWM = A: GOSUB 250: HIGH = A
140 FOR I = SETPWM TO HIGH: GET #1, A: POKE I, A: NEXT I
150 CLOSE #1
160 GR. 0 : REM Init graphics mode, set PORTA bit 0 direction
165 POKE 54018, 56: POKE 54016, 1: POKE 54018, 60
170 A = USR(SETPWM) : POS = 15 : REM Init
180 OPEN #1, 4, 0, "K:"
190 ? "Press + or -"
200 GET #1, A
210 IF A = ASC("+") THEN POS = POS + 1
220 IF A = ASC("-") THEN POS = POS - 1
230 ? "Set POS = "; POS: A = USR(SETPWM, POS)
240 GOTO 200 : REM Again
250 REM Read 2 bytes from file
260 GET #1, A: GET #1, B: A = A + B * 256: RETURN
Attached is an ATR image including MYDOS, the above basic program "TESTPWM.BAS" and the "PWM.OBX" binary, boot the atari and from basic simply RUN "D:TESTPWM.BAS".

 

Now, I will try to find the bug if the passed value is less than 24 at the start...

pwm.atr

pwm.obx

  • Like 1
Link to comment
Share on other sites

I will give this a test tomorrow when I go to the shop. As for the bug that I experienced on the first run yesterday. I was approximating that it required first starting at 25 to get things unstuck and the PWM signal to begin. In retrospect I think what the problem most likely was, is that my routine started too low (probably at zero), and then required me to get to 15 before things began to come to life. So with that said there may not be a bug, but I'll know more tomorrow.

 

Thanks again for taking the time, and doing the work to create a background PWM for the A8.

 

- Michael

Link to comment
Share on other sites

Hi Daniel,

 

After adding Turbo Basic XL (version 1.5) to the 'pwm.atr' and setting it to autorun (TBXL.AR0), I ran the program TESTPWM.BAS and got the prompt "Press + or -" (without PWM being generated). So I pressed the '+' and "Set POS = 16" was displayed, but still no PWM being generated. At POS = 24 we have PWM, and then reversing direction down to 14 progressively decrements the duty cycle. So this is all quite usable as far as I'm concerned, but I guess there really is a 'little' bug after all.

 

How about the 'BIG' bug? Hitting break and then trying to re-run the program will result in a lock-up, so apparently this is still a problem. Not terribly so, since the program is very reliable if left running.

 

I also created a new image using DOS 2.5 instead of MyDOS, and got the exact same results.

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

3. Set NUM to 25 -- NUM=25 : do what you want following such as A=USR(1536,25)

 

I don't mind looking like the fool here with my mediocre BASIC talents, but the only variable I know of that absolutely doesn't need to be set before use is A=USR call. You have to DIM a string, you have to set variables. Other BASIC actually have a SET operative and require it's use religiously, Atari notably doesn't and can fly without - sometimes. Ok, most times then, but maybe this is the very sometime it doesn't fly so good?

 

I assume here that NUM<240 is the hang up with previously unused NUM variable, in 'normal' use it would have an unused base value of 1 but here it's being put to use in a 'complexed' logical compare WITH the first use and those two functions might not like being so close together inside BASIC P code. SETting it first avoids having to crawl back out of an IF/AND situation to find a value for NUM that really doesn't yet exist. And it may be that the IF/AND fails if we then have to 'give' the default value for NUM.

 

Opps I missed this post until today. Keep in mind that that was pseudo code just to show an example of the general program flow. It was not meant to be 'real' Basic code which it was not. Sorry for the confusion.

 

- Michael

  • Like 1
Link to comment
Share on other sites

I incorporated dmsc's PWM routine into my EE Valve Stepper Control Program, and added a simple low pass filter to create an analog voltage output which I'll monitor through a DasyLab program on a PC.

0ZSPq2T.png

It works quite well, and gives me approximately 10mv per step resolution.

 

- Michael

  • Like 3
Link to comment
Share on other sites

That's better than a number of retail options out there! Glad to have your exploration and experimentation, reminds me of when it all began so long ago and everything was new and being tried... Amazing stuff from minds trying things in unexpected ways .

 

So glad to see all this and where it leads to!

 

_The Doctor__ tips his hat to Michael and Dan

  • Like 2
Link to comment
Share on other sites

That's better than a number of retail options out there! Glad to have your exploration and experimentation, reminds me of when it all began so long ago and everything was new and being tried... Amazing stuff from minds trying things in unexpected ways .

 

So glad to see all this and where it leads to!

 

_The Doctor__ tips his hat to Michael and Dan

 

Thanks :)

 

The analog output still has a slight amount of ripple when viewed on a scope, but when sent through the averaging circuit of a DVM it's steady as can be. If I need to, I can apply a similar averaging in the DasyLab program I'll be writing, but I doubt if it'll be required. With a 10mv window representing 225 possible stepper motor positions, it should be quite good.

 

Yep pretty amazing the uses that these little Atari's can be used for. Its not just all fun and games, although there is nothing wrong with that either.

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...