Fixed length pulse train challenge

edmunds

Senior Member
Dear all,

Here is a challenge.

How would you go about generating a fixed number of pulses in the background with picaxe, if you are not allowed to use settimer count? On top of that, both, HPWM and PWM are already used for other functions. Solutions can include external hardware. Preferably tiny :).

To elaborate:

1)hardware is 40x2;
2)pulses should be more or less a square wave with period of approx. 500us and there would be between 1 and 200 such pulses to issue;
3)in the background means only issuing the pulses should take me away from the main program and worst case - stopping (i.e. interrupt);
4)settimer count is already busy counting elsewhere, thus it cannot be used (it could be used by feeding some pin back to it to count pulses);
5)hpwm is used in half-bridge mode, i.e. outputs C and D are used; pwm output (C.1) is used to adjust brightness of a LED array;

The purpose is driving a stepper motor driver IC with STEP and DIR inputs with less attention from the main program. Clearly, using a separate picaxe is a solution, but this being the only reason for a separate chip, it becomes expensive in many ways (the least of which is the cost of the chip itself).

Basically there are three non-blocking ways of generating a square wave that come to mind - PWM, SR Latch and HSPI2 (HI2C1 occupied). PWM is kind of used up. SR Latch is tempting, but the fundamental issue remains - how to stop it when the required number of pulses have been issued? HSPI2 output could be interesting - if consecutive 10101010 bytes would be sent on data output and clock set to double the frequency required, this could work, but requires hacking the second MSSP module. Not trivial, but has been documented. On top of that, forming the actual spi command might turn out not to be very fast.

I have been looking for integrated devices, but there is only one I have found and it is huge (by my standards) - PCA9629. I have looked for some sort of serial counter that I could send a number 154 and it would pulse a pin on its own for 154 times, but I'm no good with 74xx and 40xx devices, so it is very well possible I have missed something.

Brainstorm, please :).

Thank you for your inputs,

Edmunds
 

hippy

Technical Support
Staff member
I would use a separate PICAXE, an 08M2 would probably do it, and that's available in surface mount so minimal size..

I cannot see any way it can be done on the 40X2 because it cannot be dedicated to the task, will be doing something else, so the requirements cannot be met.
 

edmunds

Senior Member
I would use a separate PICAXE, an 08M2 would probably do it, and that's available in surface mount so minimal size..

I cannot see any way it can be done on the 40X2 because it cannot be dedicated to the task, will be doing something else, so the requirements cannot be met.
@hippy, thanks, but the 40x2 in UQFN package takes significantly less board space and volume than the standard surface mount 08M2. And it supports I2C slave mode, so it does not require any extra pins on the master for communication.

Edmunds
 

AllyCat

Senior Member
Hi,

Brainstorm, please :).
OK, have you considered HSEROUT at about 4800 baud (=208 us pulse or space width) ? ;)

IIRC the Start is actually logic '0' and it's lsb first, so $55 should generate 5 cycles of 2.4 kHz ( Stop{1} 0 1 0 1 0 1 0 1 {0}Start). Obviously you'd have to write a character sequence into a buffer (scratchpad), send a variable number of bytes (i.e. there's always a start pulse) and perhaps use SFRs to change the configuration (e.g. the number of stop bits and a "non-standard" baud rate). I don't know exactly what hardware is available in the 40X2 and you may need to go to the base PIC data sheet for some of the hardware/pin options.

Cheers, Alan.
 

BESQUEUT

Senior Member
This can be done with a Cooperative_multitasking approach.
But you have to understand how this works...
Basically there is one (and only one) main loop wich have to run as quickly as possible.
Pause statement is prohibited, so you need a "clock" for any time related action.

At least, this can be used for LED brightness (wich is less time critical), to free hpwm.
 

edmunds

Senior Member
Hi,



OK, have you considered HSEROUT at about 4800 baud (=208 us pulse or space width) ? ;)

IIRC the Start is actually logic '0' and it's lsb first, so $55 should generate 5 cycles of 2.4 kHz ( Stop{1} 0 1 0 1 0 1 0 1 {0}Start). Obviously you'd have to write a character sequence into a buffer (scratchpad), send a variable number of bytes (i.e. there's always a start pulse) and perhaps use SFRs to change the configuration (e.g. the number of stop bits and a "non-standard" baud rate). I don't know exactly what hardware is available in the 40X2 and you may need to go to the base PIC data sheet for some of the hardware/pin options.

Cheers, Alan.
Alan, thanks, that could work, but the initial spec is then missing that HSEROUT is taken as well. One thing I have been considering is an external (just digital or even I2C) switch that could switch the HSEROUT pin between two or more devices. I'm not short of general I/Os, at least not yet. Because this pin now seems something that everybody[thing] wants in my project. Who would have thought :). SFRs would not really scare me, I do need to delve into them and actually would find it quite fun as I think I'm starting to understand at least bits and pieces of microchip data sheet to the level I could try and apply some.

Thank you for your time,

Edmunds
 

edmunds

Senior Member
This can be done with a Cooperative_multitasking approach.
But you have to understand how this works...
Basically there is one (and only one) main loop wich have to run as quickly as possible.
Pause statement is prohibited, so you need a "clock" for any time related action.
Dear Besquet,

Good to have you onboard. I think I understand this (not to sound arrogant or something :)) and this is exactly how I have arrived at a solution I could use a single picaxe for doing everything except pulsing the stepper, which there is simply not enough time for. But maybe, just maybe, I can push this idea further and actually squeeze the pulsing in between things, but then I have to split every pulsing iteration up. Need to think how to do that in a speedy way ...


Thank you for your input,

Edmunds
 

westaust55

Moderator
@hippy, thanks, but the 40x2 in UQFN package takes significantly less board space and volume than the standard surface mount 08M2. And it supports I2C slave mode, so it does not require any extra pins on the master for communication.

Edmunds
Hi Edmunds,

Looking at the 40X2 datasheet (page 527) the UQFN package is approx 5.5 mm x 5.5 mm
http://ww1.microchip.com/downloads/en/DeviceDoc/40001412G.pdf

The 08M2 in SMD SOIC package by the datasheet (page 392) is approx 3.7 mm x 2.4 mm
http://ww1.microchip.com/downloads/en/DeviceDoc/40001441F.pdf

So based upon your Specification: "Solutions can include external hardware. Preferably tiny"
I propose that hippy's suggest needs your further consideration.
 

Buzby

Senior Member
Put the SOIC 08M2 on the opposite side of the PCB, under the 40X2. This uses no board space, but will make it slightly thicker :)
 

edmunds

Senior Member
The 08M2 in SMD SOIC package by the datasheet (page 392) is approx 3.7 mm x 2.4 mm
http://ww1.microchip.com/downloads/en/DeviceDoc/40001441F.pdf
Hmm, I cannot see that. I'm clicking your link and on page 392 I get spec for QFN package which is 3.0x3.0. SOIC spec is on 385 and says 3.90 x 4.90 which would also be standard SOIC. The smaller one, I think is usually called TSSOP8 and that would really be an interesting option. However, 3.90 x 4.90 + the leg space is way too close to 5.0x5.0 of UQFN (page 526) to bother.


Thank you for your input,

Edmunds
 

hippy

Technical Support
Staff member
Using HSEROUT works for an 08M2 at 32MHz ...

Code:
#Picaxe 08M2
#No_data

SetFreq M32
HSerSetup 4000, %010
Do
  b0 = 18        ; Send 18 pulses
  b1 = b0 // 5
  LookUp b1, (0,$FF,$FD,$F5,$D5), b1
  Do While b0 >= 5
    HserOut 0,($55)
    b0 = b0 - 5
  Loop
  If b1 > 0 Then
    HserOut 0, (b1)
  End If
  Pause 800
Loop
 

Attachments

edmunds

Senior Member
Dear all,

I have succeeded with the original intent and the part missing is a mere technicality and really an extra, I think. Here is the proposed solution, code to follow soon. This took a lot of data sheet reading and head banging on the table and a little more of that is still required to complete the challenge. Here is the basic workflow:

Physical connections required:
1) CCP5 output to INT0/FTL0 (actually, one of the comparator inputs could be used to save a hw interrupt as well if 5b) works)
2) Clock source output to T5CKI

1) Start CCP5 in Compare mode
2) Start Timer5 in external counter mode
3) Set up clearing/setting CCP5 output on TMR5H:TMR5L and CCPR5H:CCPR5L match
3) Set CCPR5H:CCPR5L to desired number of pulses
4) Start clock source
5a) Use picaxe interrupt on INT0 to stop the clock source and to reset everything that needs to be reset.
5b) Set CCP3 as a clock source, enable auto-shutdown and auto-reset on FLT0 low/high depending on 3) and forget about it

The only part not working so far is 5b) that is a step further than I ever hoped to get. It somewhat works for CCP1, but I cannot get CCP3 fired up. Must be because of all the head banging :).

Disclaimer: none of this is tested with other picaxe functions using timers (that said, there seem to be so many alternative options for the ones I have used, that a combination that works should be possible to find for any project). This is all totally unsupported by RevEd for known and mostly good reasons, so whatever ideas you are now playing with in your head are at your own risk.

Cheers,

Edmunds
 
Last edited:

edmunds

Senior Member
Code down to 5a) from above

Not all of this is strictly needed, better more than less for testing, however.

Code:
#rem
Connect clock/pulse source (B.7 with this example) to C.2 on 40X2.

From a forum post by Technical:
  timer0 used in large number of commands, including touch
  timer1 settimer
  timer2 pwmout and servo
  timer3 user
  timer4 pwmout
  timer6 pwmout

timer5 is never explained, assuming available if one wants to use it.
If otherwise, changing to timer3 is not a problem, but should multiplex the input to B.5 in most cases.

On 40X2 the following pins are relevant for timers:
  B.4 - T5G
  B.5 - T3CKI,T1G
  C.0 - T1CKI(settimer count),T3CKI,T3G
  C.2 - T5CKI
  SI  - T0CKI
Default pin for T3CKI is C.0, but it can be multiplexed away to B.5 by clearing T3CMX in CONFIG3H.

Analyzing pinouts, one can assess, picaxe hpwm commands use ECCP1 module.
Only one output of ECCP2 is used pin C.1 for pwmout command.
ECCP3, CCP4 and CCP5 seem to be unused by picaxe firmware.
#endrem

#picaxe 40x2
#no_data
#no_table

{Symbol PMD0     = $3F
Symbol PMD1     = $3E
Symbol PMD2     = $3D

Symbol T2CON    = $BA
Symbol T4CON    = $51

Symbol TMR5H    = $50
Symbol TMR5L    = $4F
Symbol T5CON    = $4E
Symbol T5GCON   = $4D

Symbol PR2      = $BB
Symbol PR4      = $52

Symbol PIR4     = $7B
Symbol PIR5     = $7E
Symbol PIE5     = $7D

Symbol CCPR3H   = $5F
Symbol CCPR3L   = $5E
Symbol CCP3CON  = $5D
Symbol PWM1CON  = $B7
Symbol PWM3CON  = $5C
Symbol ECCP1AS  = $B6
Symbol ECCP3AS  = $5B
Symbol PSTR3CON = $5A
Symbol CCPR5H   = $56
Symbol CCPR5L   = $55
Symbol CCP5CON  = $54

Symbol CCPTMRS0 = $49
Symbol CCPTMRS1 = $48}


Symbol TMR5GIF = bit1
Symbol Counter = b4

init:
;  setfreq em64
  output A.7
  'clear timer registers, just in case
  pokesfr TMR5L,  $00
  pokesfr TMR5H,  $00
  'CCP5 on in compare mode, CCP5 (A.7) is cleared/low on timer5 match with CCP5 result below
  pokesfr CCP5CON, %00001001
  pokesfr CCPTMRS1, %00001000
  'preload CCP5 result, 10 pulses for testing
  pokesfr CCPR5H, $00
  pokesfr CCPR5L, $0A
  'timer5 ON in count mode, could not get 16bit TMR5x register read to work
  pokesfr T5CON,  %10000001
  pokesfr T5GCON, %01000000
  'interrupts
  pokesfr PIE5,%010            'reset interrupt
  
main:
  do
    sertxd("Starting",CR,LF)
    high A.7
    Counter = 0
    do
      inc Counter
      low B.7
      pulsout B.7,400
      peeksfr TMR5L, b54
      peeksfr TMR5H, b55
      peeksfr CCPR5L, b52
      peeksfr CCPR5H, b53
      peeksfr PIR4, b1
      peeksfr PIR5, b0
      sertxd("Loop#: ",#counter," | TMR5H: ",#w27," | CCPR5H: ",#w26," | PIR4: ",#b1," | PIR5: ",#b0,CR,LF)
      if pinB.0 = 0 then             'connected to CCP5 output (A.7)
        sertxd("Compare worked!",CR,LF)
        pokesfr PIR4,%000            'clear CCP compare interrupt flag bit
        pokesfr PIR5,%000            'clear timer5 overflow interrupt flag bit
        'reset CCP in compare mode to set CCP low on match with timer5
        pokesfr CCP5CON, %00001001
        pokesfr CCPTMRS1, %00001000
        'timer preload
        pokesfr TMR5L,$00            'set back to zero
        pokesfr TMR5H,$00
        'timer ON in count mode
        pokesfr T5CON,  %10000001
        pokesfr T5GCON, %01000000
        'timer interrupt
        pokesfr PIE5,%010            'reset interrupt
      endif
      pause 5
    loop until b1 = 4                'loop until there is a match
    sertxd("Next...",CR,LF)
    pause 500
  loop
Cheers,

Edmunds
 

edmunds

Senior Member
Yet another step closer :). I can now control pwm output with a switch on INT0 for demo. Three pins are available for this - INT0 and both comparators. High and low state can be selected for trigger and the three inputs can be combined in several combinations. Could be useful in many projects.

However, there is a problem with my POKESFRed PWM initialisation sequence. It only works, if I use hpwm before. This seems to suggest I'm forgetting to do something, but I have gone over the data sheet routine (14.4.8) a gazillion times and cannot see a mismatch. The code below also reports on all registers that I think are important and the values are the same for both approaches. Any ideas? Or maybe somebody with access to picaxe firmware source code can glean over in the source code to give me a tiny, tiny hint? :)

Code:
#picaxe 40x2
#no_data
#no_table


{Symbol PMD0     = $3F
Symbol PMD1     = $3E
Symbol PMD2     = $3D

Symbol TRIS_E   = $96
Symbol TRIS_D   = $95
Symbol TRIS_C   = $94   'have to use underscore, TRISC variable taken by firmware
Symbol TRIS_B   = $93
Symbol TRIS_A   = $92

Symbol T1CON    = $CD
Symbol T2CON    = $BA
Symbol T4CON    = $51

Symbol TMR4     = $53
Symbol TMR5H    = $50
Symbol TMR5L    = $4F
Symbol T5CON    = $4E
Symbol T5GCON   = $4D

Symbol PR2      = $BB
Symbol PR4      = $52

Symbol PIR1     = $9E
Symbol PIR2     = $A1
Symbol PIR3     = $A4
Symbol PIR4     = $7B
Symbol PIR5     = $7E
Symbol PIE1     = $9D
Symbol PIE2     = $A0
Symbol PIE3     = $A3
Symbol PIE4     = $7A
Symbol PIE5     = $7D

Symbol CCPR1H   = $BF
Symbol CCPR1L   = $BE
Symbol CCPR3H   = $5F
Symbol CCPR3L   = $5E
Symbol CCP3CON  = $5D
Symbol CCP1CON  = $BD
Symbol PWM1CON  = $B7
Symbol PWM3CON  = $5C
Symbol ECCP1AS  = $B6
Symbol PSTR1CON = $B9
Symbol ECCP3AS  = $5B
Symbol PSTR3CON = $5A
Symbol CCPR5H   = $56
Symbol CCPR5L   = $55
Symbol CCP5CON  = $54

Symbol CCPTMRS0 = $49
Symbol CCPTMRS1 = $48}

  'set up clock output on P3A(A.5)
;  hpwm pwmdiv16, pwmsingle, pwmHHHH, %0010, 255, 511
;  input B.5                    'set PWM output as input to prevent jitter during configuration
;  input B.0
;  pokesfr PSTR3CON, %00000010  'set P3A(B.5) for PWM, rest as I/Os
;  pokesfr CCPTMRS0, %01000000  'use timer 2 for PWM (may have to adjust)
;  pokesfr PR4,      %11111111  'set PWM period, 255
;;  pokesfr ECCP3AS,  %01000000  'Auto-shutdown enable on FLT0 pin (B.0) low
;  pokesfr CCP3CON,  %00001100  'PWM, half bridge module, %11 LSBs for duty cycle of 512, A polarity high
;  pokesfr CCPR3L,   %01111111  'The rest of the duty cycle
;  pokesfr T4CON,    %00000110  'Postscale 1:1, timer2 ON, prescaler 16
;  output B.5
;;  pokesfr PWM3CON,  %10000000  'Set auto-shutdown to clear when FLT0 set high


'fresh attempt
;  pokesfr TRIS_D,     %00100000  'Set D.5 an input for setup
;  pokesfr PSTR1CON,   %00000010  'set P1B(D.5) for PWM, rest as I/Os
;  pokesfr CCPTMRS0,   %00000001  'use timer4 resource for PWM (may have to adjust)
;  pokesfr PR4,        %11111111  'set PWM period, 255
;  pokesfr ECCP1AS,    %00000000  'Auto-shutdown off for now
;  pokesfr PWM1CON,    %10000000  'Set auto-shutdown to clear
;  pokesfr ECCP1AS,    %10000000  'Set CCP1ASE bit
;  pokesfr CCP1CON,    %00111100  'PWM, half bridge module, %11 LSBs for duty cycle of 512, A polarity high
;  pokesfr CCPR1L,     %01111111  'The rest of the duty cycle
;  pokesfr T4CON,      %00000100  'Postscale 1:1, timer4 ON, no prescaler
;  pokesfr TRIS_D,     %00000000  'Set D.5 an output for operation
;  pokesfr ECCP1AS,    %00000000  'Clear CCP1ASE bit
  
  
main:
  hpwm pwmdiv16, pwmsingle, pwmHHHH, %0010, 255, 511
  sertxd("PICAXE HPWM COMMAND REGISTERS",CR,LF)
  gosub print_registers
  hpwm OFF
  pokesfr TRIS_D,     %00100000  'Set D.5 an input for setup
  pokesfr PSTR1CON,   %00000010  'set P1B(D.5) for PWM, rest as I/Os
  pokesfr CCPTMRS0,   %00000001  'use timer4 resource for PWM (may have to adjust)
  pokesfr PR4,        %11111111  'set PWM period, 255
;  pokesfr ECCP1AS,    %01000000  'Auto-shutdown on FLT0 pin low
  pokesfr PWM1CON,    %00000000  'Set auto-shutdown to clear
  pokesfr ECCP1AS,    %11000000  'Set CCP3ASE bit and Auto-shotdown on FLTO pin low
  pokesfr CCP1CON,    %00111100  'PWM, half bridge module, %11 LSBs for duty cycle of 512, A polarity high
  pokesfr CCPR1L,     %01111111  'The rest of the duty cycle
  pokesfr T4CON,      %00000110  'Postscale 1:1, timer4 ON, no prescaler
  pokesfr TRIS_D,     %00000000  'Set D.5 an output for operation
;  pokesfr ECCP1AS,    %00000000  'Clear CCP1ASE bit
  pokesfr PWM1CON,    %10000000  'Start PWM
  sertxd("POKESFRed ECCP MODULE REGISTERS",CR,LF)
  gosub print_registers
  do:loop

print_registers:
  peeksfr PSTR1CON, b0         'peek PSTR1CON setup
  sertxd("1. PSTR1CON, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr CCPTMRS0, b0         'peek CCPTMRS0 setup
  sertxd("2. CCPTMRS0, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr ECCP1AS, b0         'peek ECCP1AS setup
  sertxd("3. ECCP1AS, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr PWM1CON, b0         'peek PWM1CON setup
  sertxd("4. PWM1CON, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr CCP1CON, b0         'peek CCP1CON setup
  sertxd("5. CCP1CON, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr T4CON, b0         'peek T4CON setup
  sertxd("6. T4CON, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr PR4, b0         'peek PR4 setup
  sertxd("7. PR4, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next

  sertxd(CR,LF)
  peeksfr CCPR1L, b0         'peek CCPR1L setup
  sertxd("8. CCPR1L, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr T1CON, b0         'peek T1CON setup
  sertxd("9. T1CON, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)

  peeksfr PMD0, b0         'peek PMD0 setup
  sertxd("10. PMD0, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next

  sertxd(CR,LF)
  peeksfr PMD1, b0         'peek PMD1 setup
  sertxd("11. PMD1, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next

  sertxd(CR,LF)
  peeksfr PMD2, b0         'peek PMD2 setup
  sertxd("12. PMD2, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)
return
Thank you for your input,

Edmunds
 
Last edited:

hippy

Technical Support
Staff member
Code:
  peeksfr PMD2, b0         'peek PMD2 setup
  sertxd("12. PMD2, %")
  for b1 = 7 to 0 step -1
    if b0 bit b1 set then
      sertxd("1")
    else
      sertxd("0")
    endif
  next
  sertxd(CR,LF)
You can compact that and similar down to -

Code:
  peeksfr PMD2, b0
  sertxd("12. PMD2, %",#bit7,#bit6,#bit5,#bit4,#bit3,#bit2,#bit1,#bit0,CR,LF)
Even create a #MACRO then you can just use -

Code:
  Dump( "12. PMD2", PMD2 )
 

edmunds

Senior Member
I put all of it together and this is actually doing what I want. You can send up to 65535 pulses and it will cost you only 250uS running at 64MHz and you can do whatever you like while the hardware is pulsing. If you are not sure, you are done pulsing you can poll the interrupt and loop before issuing the next pulse train, of course. With careful use of timers and CCP modules, you could set up two such instances and run, say, two steppers for a differential drive robot with comparable overhead of turning a servo (roughly 100uS).

The only trouble is, it is on the main hpwm output and I would like to push the stepper clock generation to (E)CCP3. So, the cry for help in the earlier post (#15) stands.

Code:
#picaxe 40x2
#no_data
#no_table


{'Symbols
Symbol PMD0     = $3F
Symbol PMD1     = $3E
Symbol PMD2     = $3D

Symbol TRIS_E   = $96
Symbol TRIS_D   = $95
Symbol TRIS_C   = $94   'have to use underscore, TRISC variable taken by firmware
Symbol TRIS_B   = $93
Symbol TRIS_A   = $92

Symbol T1CON    = $CD
Symbol T2CON    = $BA
Symbol T4CON    = $51

Symbol TMR4     = $53
Symbol TMR5H    = $50
Symbol TMR5L    = $4F
Symbol T5CON    = $4E
Symbol T5GCON   = $4D

Symbol PR2      = $BB
Symbol PR4      = $52

Symbol PIR1     = $9E
Symbol PIR2     = $A1
Symbol PIR3     = $A4
Symbol PIR4     = $7B
Symbol PIR5     = $7E
Symbol PIE1     = $9D
Symbol PIE2     = $A0
Symbol PIE3     = $A3
Symbol PIE4     = $7A
Symbol PIE5     = $7D

Symbol CCPR1H   = $BF
Symbol CCPR1L   = $BE
Symbol CCPR3H   = $5F
Symbol CCPR3L   = $5E
Symbol CCP3CON  = $5D
Symbol CCP1CON  = $BD
Symbol PWM1CON  = $B7
Symbol PWM3CON  = $5C
Symbol ECCP1AS  = $B6
Symbol PSTR1CON = $B9
Symbol ECCP3AS  = $5B
Symbol PSTR3CON = $5A
Symbol CCPR5H   = $56
Symbol CCPR5L   = $55
Symbol CCP5CON  = $54

Symbol CCPTMRS0 = $49
Symbol CCPTMRS1 = $48

Symbol TMR5GIF = bit1
Symbol Counter = b4
}

init:
  setfreq em64
  output A.7
'Initialise PWM, CCP1 for now, cannot get CCP3 operational
  hpwm pwmdiv16, pwmsingle, pwmHHHH, %0010, 255, 511
  hpwm OFF
  pokesfr TRIS_D,     %00100000  'Set D.5 an input for setup
  pokesfr PSTR1CON,   %00000010  'set P1B(D.5) for PWM, rest as I/Os
  pokesfr CCPTMRS0,   %00000001  'use timer4 resource for PWM (may have to adjust)
  pokesfr PR4,        %11111111  'set PWM period, 255
  pokesfr PWM1CON,    %00000000  'Set auto-shutdown to clear
  pokesfr ECCP1AS,    %11000000  'Set CCP3ASE bit and Auto-shotdown on FLTO pin low
  pokesfr CCP1CON,    %00111100  'PWM, half bridge module, %11 LSBs for duty cycle of 512, A polarity high
  pokesfr CCPR1L,     %01111111  'The rest of the duty cycle
  pokesfr T4CON,      %00000110  'Postscale 1:1, timer4 ON, no prescaler
  pokesfr TRIS_D,     %00000000  'Set D.5 an output for operation
  pokesfr PWM1CON,    %10000000  'Start PWM
'clear timer registers, just in case
  pokesfr TMR5L,  $00
  pokesfr TMR5H,  $00
'CCP5 on in compare mode, CCP5 (A.7) is cleared/low on timer5 match with CCP5 result below
  pokesfr CCP5CON, %00001001
  pokesfr CCPTMRS1, %00001000
'preload CCP5 result, 10 pulses for testing
  pokesfr CCPR5H, $00
  pokesfr CCPR5L, $0A
'timer5 ON in count mode, could not get 16bit TMR5x register read to work
  pokesfr T5CON,  %10000001
  pokesfr T5GCON, %01000000
'interrupts
  pokesfr PIE5,%010            'reset interrupt

main:
do
  for Counter = 3 to 15
'time the loop
;    high B.7
'load the number of pulses wanted into CCPR5L
    pokesfr CCPR5L, Counter
'reset CCP in compare mode to set CCP low on match with timer5
    pokesfr CCP5CON, %00001001
'reset timer5 result registers to zero again
    pokesfr TMR5L,$00
    pokesfr TMR5H,$00
'take A.7 high to re-start PWM
    high A.7
'stop timing the loop
;    low B.7
    pause 800
  next
loop
Cheers,

Edmunds

EDIT: Here is a little video of scope output on D.5 (hpwmB) pin.
 
Last edited:

erco

Senior Member
Good progress Edmunds, sounds like you're closing in on a solution.

Not exactly the same problem, but I'll share a clever coding trick to generate pulses. The tip likely came from hippy or technical. An 08M2 beacon project was PWMing 38 kHz out to an IR LED. I needed to pulse that modulated IR at several different rates. Typically I connect an IR LED between 2 output pins, one PWMing at 38 kHz and the other pulsing much slower. Always works fine but I was out of pins, including serial out pin C.0.

I could have manually switched PWM output on & off, but what was simpler, faster, and far more compact code was to leave PWM on and "toggle" the pin between INPUT and OUTPUT modes as it loops though the program. PWM continues running internally but INPUT disconnects it from that pin, OUTPUT reconnects it. My first time using those commands and it saved my bacon.
 

edmunds

Senior Member
Good progress Edmunds, sounds like you're closing in on a solution.

Not exactly the same problem, but I'll share a clever coding trick to generate pulses. The tip likely came from hippy or technical. An 08M2 beacon project was PWMing 38 kHz out to an IR LED. I needed to pulse that modulated IR at several different rates. Typically I connect an IR LED between 2 output pins, one PWMing at 38 kHz and the other pulsing much slower. Always works fine but I was out of pins, including serial out pin C.0.

I could have manually switched PWM output on & off, but what was simpler, faster, and far more compact code was to leave PWM on and "toggle" the pin between INPUT and OUTPUT modes as it loops though the program. PWM continues running internally but INPUT disconnects it from that pin, OUTPUT reconnects it. My first time using those commands and it saved my bacon.
Thank you. Yes, that would work and is indeed a useful idea. Had not thought to use the "switch" as a switch.

In the meantime, I have not had any progress on replicating HPWM with pokesfr commands. I tried to cheat and get assembly output for hpwm, but my PE5 said something about a missing file and reinstall did not help. I found some application note from microchip with examples in assembly. Was interesting and not too difficult, but the outcome of learning a couple of assembly commands so far is just a confirmation I seem to be doing exactly what everybody else is, but it works for them and not for me. There must be a dirty little 0/1 thing that is still in the way. Will try to read the data sheet on PWM modes again with a fresh eye tomorrow.

Cheers,

Edmunds
 
Last edited:

edmunds

Senior Member
Dear all,

An update for the day.

I have spent another few hours to try and replicate what hpwm command does with pokesfr in a hope to later replicate this into firing up CCP3 module in PWM mode. I have done some interesting things, that may be of use in the process.

I created a small program printing all [accessible] the register values of a blank picaxe. This gave some interesting insights. For an example on what timers are preset. Then, I did the same with hpwm command activated and another one on hpwm with OFF parameter. This gave me three sets of register states that were interesting to compare. However, setting them exactly how hpwm sets them through pokesfr did not produce the same results, so I must conclude hpwm reaches into the registers that are prohibited for access by picaxe firmware and are thus not fully controllable through pokesfr. I do not expect somebody from RevEd to spend a lot of time on this, but affirming or denying the results of my research would give me back some sleep :).

Now, I have the clock control built, so I only need a clock source that can be controlled by it. It is a pity I cannot get access to on-board pwm modules, of course, but so be it. Another good option for many situations would be SR Latch clock feature, which would be possible to control with the solution in above posts. However, for what I need or, more importantly, for how fast I need to clock picaxe for other needs, the clock would be way too fast to run a stepper in a single step mode. There are tiny clock source ICs, so it is a problem that is possible to solve, but this will add another interrupt to my software flow, which could mean I need to set up interrupt priorities. I now know how to set these up through pokesfr registers, this might be possible to implement. Or some other way :)

I'm going through all that length (or as some put it 'getting my money's worth', hey Stan :)) because I don't need a single vehicle. I need a couple of hundred for our own layouts in four towns and maybe some other people need some in the future as well. Having more than one thing to program and more than one code set to maintain is a PITA I would like to avoid even if the code on the steering processor would be 'minimal'.


Have a good weekend,

Edmunds
 
Last edited:

edmunds

Senior Member
I cannot help, but notice hpwm is affecting SSP1CONx registers in strange ways. IMHO this is not correct and I can see traces on the forum of there being a bug once upon a time. The chip I'm using reports B.3 firmware. I wonder if this could have anything to do with my earlier I2C problems with BNO055 as I did use hpwm at the same time for at least part of the testing I did. Would be grateful for some light shed on that.

Cheers (literally, Friday night here) :),

Edmunds
 
Last edited:

edmunds

Senior Member
I did trick CCP3 into working finally :). The code below modifies standard pwmout command to switch CCP3 into half-bridge mode.

Code:
#picaxe 40x2
#no_data
#no_table


{'Symbols
Symbol PMD0     = $3F
Symbol PMD1     = $3E
Symbol PMD2     = $3D

Symbol TRIS_E   = $96
Symbol TRIS_D   = $95
Symbol TRIS_C   = $94   'have to use underscore, TRISC variable taken by firmware
Symbol TRIS_B   = $93
Symbol TRIS_A   = $92

Symbol T1CON    = $CD
Symbol T2CON    = $BA
Symbol T4CON    = $51

Symbol TMR4     = $53
Symbol TMR5H    = $50
Symbol TMR5L    = $4F
Symbol T5CON    = $4E
Symbol T5GCON   = $4D

Symbol PR2      = $BB
Symbol PR4      = $52

Symbol PIR1     = $9E
Symbol PIR2     = $A1
Symbol PIR3     = $A4
Symbol PIR4     = $7B
Symbol PIR5     = $7E
Symbol PIE1     = $9D
Symbol PIE2     = $A0
Symbol PIE3     = $A3
Symbol PIE4     = $7A
Symbol PIE5     = $7D

Symbol CCPR1H   = $BF
Symbol CCPR1L   = $BE
Symbol CCPR3H   = $5F
Symbol CCPR3L   = $5E
Symbol CCP3CON  = $5D
Symbol CCP1CON  = $BD
Symbol PWM1CON  = $B7
Symbol PWM3CON  = $5C
Symbol ECCP1AS  = $B6
Symbol PSTR1CON = $B9
Symbol ECCP3AS  = $5B
Symbol PSTR3CON = $5A
Symbol CCPR5H   = $56
Symbol CCPR5L   = $55
Symbol CCP5CON  = $54

Symbol CCPTMRS0 = $49
Symbol CCPTMRS1 = $48

Symbol TMR5GIF = bit1
Symbol Counter = b4
}

'THIS WORKS, SO CCP3 MODULE CAN BE USED IN HALF BRIDGE MODE, OUTPUTS B.5 and A.6
init:
  setfreq em64
'Initialise PWM, CCP3 on B.5, multiplexed by picaxe firmware
  pwmout pwmdiv16, B.5, 249, 499
  input B.5 : input A.6           'make PWM pins inputs during configuration
  pokesfr CCP3CON, %10001100      'configure half-bridge mode, active high polarity for both pins
  pokesfr PWM3CON, %10001010      'PRSEN bit set, but should not matter, dead-band delay set to 10
  output B.5 : output A.6         'start PWM by enabling A and B pins as outputs
  
main:
  do
    pause 100
  loop

Good luck,

Edmunds
 

edmunds

Senior Member
Dear all, I declare victory. :)

The below code uses four of the total 5 Capture/Compare/PWM modules of 40x2 hardware. Three timers (2/4/6) are used to generate PWM signals and timer5 is used to count the pulses generated. INT0 pin is used for auto-shutdown input for CPP1 (hpwm command) module that is output on pin D.5 (stepper pulse generation). Three other pins could be used instead or along with D.5. CCP2 is running in its simplest form and generates PWM waveform to control brightness of an LED using timer2 on pin D.2 (road sensor lights). Three other pins could be used instead or along with D.2. CCP3 is running in half-bridge mode on pins B.5 and A.6 and is using timer6 (main motor).

Timer 5 is counting pulses on pin C.2 and is pulling A.7 low on match with a number set in CCP result register. A connection between A.7 and B.0 (INT0/FLT0) has to be made. Also, D.5 needs to fed into C.2 externally. This way, settimer count (uses timer1) can be used on C.0 (odometer).

I could not really figure out what picaxe pwm commands are doing and could not replicate that successfully. Instead, I used the command "as is" and adjusted the necessary registers later. There is something strange going on with Timer2 and PR2 for CCP2 module, but I assigned it to an LED, where period that does work is fine and adjusting duty cycle does not seem to cause any problems.

The only thing to wish for that I have not managed to crack, is freeing up the interrupt pin and replacing it with a comparator. On the other hand, with compflag available, comparator is almost as good as an interrupt pin, so can live without it. I will try to make this stop bugging me and do something else for a while now ;).

Code:
#rem
Connect clock/pulse source (B.7 with this example) to C.2 on 40X2.

From a forum post by Technical:
  timer0 used in large number of commands, including touch
  timer1 settimer
  timer2 pwmout and servo
  timer3 user
  timer4 pwmout
  timer6 pwmout

timer5 is never explained, assuming available if one wants to use it.
If otherwise, changing to timer3 is not a problem, but should multiplex the input to B.5 in most cases.

On 40X2 the following pins are relevant for timers:
  B.4 - T5G
  B.5 - T3CKI,T1G
  C.0 - T1CKI(settimer count),T3CKI,T3G
  C.2 - T5CKI
  SI  - T0CKI
Default pin for T3CKI is C.0, but it can be multiplexed away to B.5 by clearing T3CMX in CONFIG3H.

Further research shows PICAXE defaults to timer4 for CCP3 and timer6 for both, CCP4 and CCP5. CCP1 and CCP2 use timer2.
#endrem

#picaxe 40x2
#no_data
#no_table


{'Symbols
Symbol PMD0     = $3F
Symbol PMD1     = $3E
Symbol PMD2     = $3D

Symbol TRIS_E   = $96
Symbol TRIS_D   = $95
Symbol TRIS_C   = $94   'have to use underscore, TRISC variable taken by firmware
Symbol TRIS_B   = $93
Symbol TRIS_A   = $92

Symbol T1CON    = $CD
Symbol T2CON    = $BA
Symbol T4CON    = $51
Symbol T6CON    = $4A

Symbol TMR4     = $53
Symbol TMR5H    = $50
Symbol TMR5L    = $4F
Symbol T5CON    = $4E
Symbol T5GCON   = $4D

Symbol PR2      = $BB
Symbol PR4      = $52
Symbol PR6      = $4B

Symbol PIR1     = $9E
Symbol PIR2     = $A1
Symbol PIR3     = $A4
Symbol PIR4     = $7B
Symbol PIR5     = $7E
Symbol PIE1     = $9D
Symbol PIE2     = $A0
Symbol PIE3     = $A3
Symbol PIE4     = $7A
Symbol PIE5     = $7D

Symbol CCPR1H   = $BF
Symbol CCPR1L   = $BE
Symbol CCPR3H   = $5F
Symbol CCPR3L   = $5E
Symbol CCP3CON  = $5D
Symbol CCP1CON  = $BD
Symbol PWM1CON  = $B7
Symbol PWM3CON  = $5C
Symbol ECCP1AS  = $B6
Symbol PSTR1CON = $B9
Symbol ECCP3AS  = $5B
Symbol PSTR3CON = $5A
Symbol CCPR5H   = $56
Symbol CCPR5L   = $55
Symbol CCP5CON  = $54
Symbol CCP2CON  = $66
Symbol PSTR2CON = $63

Symbol CCPTMRS0 = $49
Symbol CCPTMRS1 = $48

Symbol TMR5GIF = bit1
Symbol Counter = b4
}

init:
  setfreq em64
'Initialise PWM, CCP2 on C.1
  pwmout pwmdiv16, C.1, 249, 499  'setting period through PR2 does not work, need to use picaxe command for CCP2
  input D.2                       'make PWM pins inputs during configuration
  pokesfr PSTR2CON,%00000010      'set P2B(D.2) for PWM, rest as I/Os
  pokesfr CCP2CON, %00001100      'configure single mode, active high polarity
  output D.2                         'start PWM by enabling A and B pins as outputs
  
'Initialise PWM, CCP3 on A.6 and B.5, the latter multiplexed by picaxe firmware
  pwmout pwmdiv16, B.5, 249, 499  'period and duty values irrelevant as switching timer away from default timer4
  input B.5 : input A.6           'make PWM pins inputs during configuration
  pokesfr PR6,     %11111111      'set timer6 period
  pokesfr CCP3CON, %10001100      'configure half-bridge mode, active high polarity for both pins
  pokesfr PWM3CON, %10001010      'PRSEN bit set, but should not matter, dead-band delay set to 10
  output B.5 : output A.6         'start PWM by enabling A and B pins as outputs
  
'Initialise PWM, CCP1 on D.5 with hardware pulse train control
  hpwm pwmdiv16, pwmsingle, pwmHHHH, %0010, 249, 499
  output A.7                      'Make CCP5 pin an output
  input D.5                       'Set D.5 an input for setup
  pokesfr PSTR1CON,   %00000010   'set P1B(D.5) for PWM, rest as I/Os
  pokesfr PR4,        %11111111   'set PWM period, 255
  pokesfr PWM1CON,    %00000000   'Set auto-shutdown to clear
  pokesfr ECCP1AS,    %11100000   'Set CCP3ASE bit and Auto-shotdown on FLT0 pin low
  pokesfr CCP1CON,    %00111100   'PWM, half bridge module, %11 LSBs for duty cycle of 512, A polarity high
  pokesfr CCPR1L,     %01111111   'The rest of the duty cycle
  output D.5                      'Set D.5 an output for operation
  pokesfr PWM1CON,    %10000000   'Start PWM
  
'easier to configure those last (instead of |) as changes affect several CCP modules
  pokesfr CCPTMRS0,%10000001      'use timer6 for CCP3, timer2 for CCP2 and timer4 for CCP1
  pokesfr T2CON,   %00001110      'Postscale 1:2, timer2 ON, 1:16 prescaler, very strange, but the only thing that works
  pokesfr T4CON,   %00000110      'Postscale 1:1, timer4 ON, 1:16 prescaler
  pokesfr T6CON,   %00000110      'Postscale 1:1, timer6 ON, 1:16 prescaler

'clear timer registers, just in case
  pokesfr TMR5L,  $00
  pokesfr TMR5H,  $00
'CCP5 on in compare mode, CCP5 (A.7) is cleared/low on timer5 match with CCP5 result below
  pokesfr CCP5CON, %00001001
  pokesfr CCPTMRS1, %00001000
'preload CCP5 result, 10 pulses for testing
  pokesfr CCPR5H, $00
  pokesfr CCPR5L, $0A
'timer5 ON in count mode, could not get 16bit TMR5x register read to work
  pokesfr T5CON,  %10000001
  pokesfr T5GCON, %01000000
'interrupts
  pokesfr PIE5,%010            'reset interrupt

main:
do
  for Counter = 3 to 15
'time the loop
;    high B.7
'load the number of pulses wanted into CCPR5L
    pokesfr CCPR5L, Counter
'reset CCP in compare mode to set CCP low on match with timer5
    pokesfr CCP5CON, %00001001
'reset timer5 result registers to zero again
    pokesfr TMR5L,$00
    pokesfr TMR5H,$00
'take A.7 high to re-start PWM
    high A.7
'stop timing the loop
;    low B.7
    pause 800
  next
loop
Cheers,

Edmunds
 
Last edited:
Top