6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue Nov 12, 2024 12:12 am

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Interrupt on pin change
PostPosted: Thu Jul 09, 2020 11:27 am 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
Currently I am working on a design of a retro digital clock, based on WDC6502. It already works, but I want to add an additional module with SPO256 voice synthesizer chip and some circuitry providing DCF77 radio time synchronization, which requires timer for measuring pulse length and pin change interrupt its edges. Timer is easy - i already used MC6840 in my earlier designs. But what about pin change interrupt?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 11:52 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
I believe the 6522 VIA and/or 6521 PIA can be set up for this.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 11:55 am 
Offline

Joined: Sat Aug 19, 2017 1:42 pm
Posts: 35
Location: near Karlsruhe, West-Germany
Atlantis wrote:
Timer is easy - i already used MC6840 in my earlier designs. But what about pin change interrupt?

A 6522 should do both.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 12:00 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Crossed in the post... my idea is more homebrew! It might be that with the VIA the ISR would have to set the sense of the next expected edge? Or are there two inputs one could use, set one up for positive edge and the other for negative.

This was my idea, anyhow:

If the pulse length is much longer than the clock, you can use the clock and a flop and an XOR to produce a pulse on each edge. (But, you need to be sure the clock is slow enough that the pulse is long enough to be sure to take the interrupt... or you could add in a set-reset latch, and use an output port to clear it from the ISR.)


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 12:29 pm 
Offline

Joined: Sat Aug 19, 2017 1:42 pm
Posts: 35
Location: near Karlsruhe, West-Germany
BigEd wrote:
If the pulse length is much longer than the clock, [...]

For evaluation the DCF77 signal you must detect clock lengths of 100msec, 200msec, 800msec, 900msec, 1800msec and 1900msec. The accuracy of the signal is (estimated) +/-10%.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 4:02 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Yep, sounds like a good application for a 6522 VIA. I'll assume that you have a clean, properly conditioned signal coming in (getting that right is mostly an analogue-domain problem) and that you only need to determine the time interval between rising and falling edges to a precision of 25ms.

The VIA has two 16-bit timers, and you can set one of them to count a specific number of CPU (Phi2) clock cycles repeatedly, and the other to count the number of cycles of the first timer. If you have a 1MHz Phi2 clock, 25ms is 25,000 cycles, which is comfortably within the range of the VIA's timers. The second timer will then increment by 40 every second, or by approximately 4, 8, 32, 36, 72, and 76 for each of the periods listed above. You can distinguish these by examining only the low-order byte of the timer.

The CA1, CA2, CB1, CB2 lines can each be set up to trigger an interrupt on a rising or falling edge. I think it's perfectly sensible to listen first for the rising edge in order to find the leading end of the pulse, record the timer value when the interrupt fires, then set it to listen instead for the falling edge. When that fires, you simply subtract the first timer value from the new one, and find the nearest value from the above list.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 10, 2020 4:59 am 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
Chromatix wrote:
The VIA has two 16-bit timers, and you can set one of them to count a specific number of CPU (Phi2) clock cycles repeatedly, and the other to count the number of cycles of the first timer. If you have a 1MHz Phi2 clock, 25ms is 25,000 cycles, which is comfortably within the range of the VIA's timers. The second timer will then increment by 40 every second, or by approximately 4, 8, 32, 36, 72, and 76 for each of the periods listed above. You can distinguish these by examining only the low-order byte of the timer.


It is a good idea. I simply considered MC6840 because I already know it (I used it in several other designs) and have number of them in my supply. Probably I also have 6522, but just one or two and I'd rather save them for some batter project. ;) There is one additional aspect - 6840 has three 16 bit timers, so I could use the last one as a general purpose timer, for example to program delay between events in easy "Arduino like" way. Instead of connecting two timers together, I could even use just one with hardware prescaler or external, slow oscillator. This way additional timer could be utilized to generate audio tones.

Originally I considered building edge detecting circuit with TTL/HCT chips. But now I consider using GAL chip. I could implement two od those detectors for each edge and store result in SR latches with tri-state outputs (connected to the data bus). Latch outputs would have been activated by correct sequence of address nad RD signals. Plus an additional output to drive OC INT buffer and input to reset latches. This could be achievable by GAL20V8, maybe even together with simple address decoder in single chip.

EDIT: I just realized that MC6840 has pulse width compare mode. It raises an interrupt if pulse at GATE input is shorter or longer than value in register. With slow enough clock signal it may be useful...


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 10, 2020 1:46 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
For the avoidance of doubt, the W65C22S and W65C22N are still in production, so it's easy to get more of them. The MC6840 is not.

But I can see how the MC6840 can be used for this purpose. Here you need to physically connect the output of one timer (in free-run mode, generating the 25ms reference pulses) to the input of another (in pulse width comparison mode). In interrupt-on-shorter-pulse mode, with the second timer set to a high value on reset, the counter will be reset and start counting on the rising edge of the pulse, and will stop counting and generate an interrupt on the falling edge; you can then read the precise pulse width out of the timer. That is exactly what you need for this application.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 11, 2020 12:20 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
Chromatix wrote:
For the avoidance of doubt, the W65C22S and W65C22N are still in production, so it's easy to get more of them. The MC6840 is not.


It doesn't mean it is always easy to buy them where I live. At this point there are four people selling 6840 on local Polish auction site. There is no one selling any version of 6522. Not even mentioning the fact that I have my owns small supply. ;)


Quote:
But I can see how the MC6840 can be used for this purpose. Here you need to physically connect the output of one timer (in free-run mode, generating the 25ms reference pulses) to the input of another (in pulse width comparison mode).


Do reference pulses really need to be precise? Can I use for example RC oscillator with 555 chip? This way it will be possible to relieve one programmable timer from this duty, to find better way of using it in this project. ;)


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 11, 2020 12:47 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Looks like you need to (fairly reliably) detect the difference between a 100ms pulse and a 200ms pulse. I suppose a relatively uncalibrated delay could manage that.
https://en.wikipedia.org/wiki/DCF77#Amp ... modulation

(All the time field data is parity-protected, so that helps a bit to detect and ignore miscaptured data.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 16, 2020 8:15 am 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
I just realized I do not need additional hardware timer. Single timer from MC6840 can be used for both: generating 25ms reference pulses for DCF77 pulse length measuring AND 25ms interrupts "systick" functionality. This leaves one free timer that can be used to generate tones.


Top
 Profile  
Reply with quote  
PostPosted: Mon Oct 19, 2020 4:10 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
Ok, I just returned to this project. Can you tell me I didn't get anything wrong and I do understand the MC6840 work correctly?

The initialization code looks as follows:

Code:
void __fastcall__ mc6840_init (void) {
    MC6840_CON13 = TM_COUNTER_OUTPUT_ENABLE  | TM_INTERUPT_DISABLE | TM_CONT_OP_MODE1 | TM_NORMAL_16BIT | TM_SYS_CLK | TMCR3_T3_CLK_NO_PRESCALER;   //CON3 first by default after reset. TIMER3 generates sound. Output enable and sys clk
    MC6840_CON2  = TM_COUNTER_OUTPUT_ENABLE  | TM_INTERUPT_ENABLE  | TM_CONT_OP_MODE1 | TM_NORMAL_16BIT | TM_SYS_CLK | TMCR2_WRITE_CR1;            //CON2 accessed directly..TIMER2 is used for systick and time base for DCF77. Output enabled and sys clk.
    MC6840_CON13 = TM_COUNTER_OUTPUT_DISABLE | TM_INTERUPT_ENABLE | TM_PULSE_WIDTH_COMP_MODE1 | TM_NORMAL_16BIT | TM_EXT_CLK | TMCR1_ALL_TIMERS_ALLOWED;   //CON1. TIMER1 to measure DCF77 pulses length, so external source and interrupt enabled.
   //Remember about endianess - MC6800 family is big endian, 6502 is little endian. Remember that timer is decremented.
   MC6840_TIMER1 = Swap2Bytes(0xFFFF);
    MC6840_TIMER2 = Swap2Bytes(0x9E57);       //25ms interrupt (0xFFFF - 25000) - it is decremented!
    MC6840_TIMER3 = Swap2Bytes(0xF82F);       //500 Hz signal on audio output
}


There is an interrupt routine for TIMER1 (set in pulse width mode):

Code:
           LDA MC6840_STA         ; Load TIMER status register
           AND #$01               ; Check if TIMER1 IRQ flag is set
           BEQ irq_chk_rtc        ; If flag is cleared, go to the next stage
           LDA MC6840_TIMER1      ; You must read T1 to clear interrupt flag
           TAX                 ; This is MSB, transfer it to X                   
           LDA MC6840_TIMER1+1     ; This is LSB, it stays in A
           JSR _dcf_analyze        ; DCF77 being processed here
           LDA #$FF              ; Reload timer
           STA MC6840_TIMER1     ; MSB Fir
           STA MC6840_TIMER1 + 1  ; Then LSB     


This is a dcf_analyze function:

Code:
void __fastcall__ dcf_analyze (uint16_t len) {
   uint8_t tmp, tmp2;
   uint16_t pulse_len;
   
   pulse_len = 0xFFFF - len;                     //Timer counts in reverse, so we need to convert
   
   tmp=dcf_count/8;
   tmp2=dcf_count%8;
   
   if (pulse_len < 3) {                        //Pulse shorter than 75ms (3*25ms) - invalid
      dcf_count = 0;                           //Clear bit count
   }
   else if (pulse_len >= 3 && pulse_len <= 5) {      //Valid bit 0 75-125 ms (100 ms)
      dcf_data[tmp] = dcf_data[tmp] & (~(1<<tmp2));    //writnig 0
      dcf_count++;                            //next bit   
   }
   else if (pulse_len >= 7 && pulse_len <= 9) {      //Valid bit 1 175-225 ms (200 ms)
      dcf_data[tmp] = dcf_data[tmp] | (1<<tmp2);       //writnig 1
      dcf_count++;                            //next bit         
   }
   else if (pulse_len > 39 && pulse_len < 84) {      //Valid synchro null 59bit (975-2100 ms)
      dcf_count = 0;
   }
   
   if (dcf_count > 58) {                        //End of receiving, now validate data
      dcf_count = 0;                           //Prevent buffer overflow
      memcpy(dcf_work_buffer, dcf_data, 8);         //Copy received data to work buffer, it will be processed in main loop
      dcf_frame_received = 1;
   }
}


Tell mi if I understand it correctly:
1. At the beginning, timer should be preloaded with 0xFFFF.
2. It stays still until GATE1 signal goes down.
3. It is decrementing initial timer value (0xFFFF) by 1 with every clock cycle on C1 input (which in my case is 25ms).
4. When GATE1 goes up, it starts counting and interrupt is executed.
5. I need to read the value stored in TIMER1 register, remembering to swap the bytes, because 6502 is little endian.
6. To get the actual number of "ticks" counted while GATE1 was low, I need to subtract this value from 0xFFFF.
7. Then I need to load TIMER1 with 0xFFFF once again, because otherwise it would start the next count from its last value. It doesn't reload itself automatically, Am I right?

Is there some mistake in my thinking?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 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:  
cron