Shop OBEX P1 Docs P2 Docs Learn Events
TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++ - Page 28 — Parallax Forums

TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++

12526283031109

Comments

  • bmentinkbmentink Posts: 107
    edited 2013-07-24 02:03
    Hi Peter,

    Is there any more example code for the COG timers? I have studied the wave playing example and sort of understand it (been wading through the Parallax docs), would be good to
    have some other other examples though ... i.e pulse PWM, motor control, Freq/Duty measurement etc ... the timers are so powerful, I would like to get my head around them ...

    Cheers,
    Bernie
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-24 05:29
    bmentink wrote: »
    Hi Peter,

    Is there any more example code for the COG timers? I have studied the wave playing example and sort of understand it (been wading through the Parallax docs), would be good to
    have some other other examples though ... i.e pulse PWM, motor control, Freq/Duty measurement etc ... the timers are so powerful, I would like to get my head around them ...

    Cheers,
    Bernie
    There's the PWM code that's built in for 8 channels although it's a fairly easy matter to make it 32 channels so that you can choose arbitrary pins to suit. There's also the DAC function which could just as easily have a VOLTS function frontend to make it easier to set a voltage. So besides these and the frequency generation words that you can play with I think that it's easy enough to go to the next step of measuring etc. Have you had a look at the Introduction page? If you have something specific in mind I can work on that.
  • RickInTexasRickInTexas Posts: 124
    edited 2013-07-24 09:24
    I actually have the W5200 code and FAT32 file + virtual memory available soon. It's all been dragging out as a WIP until I start feeling the whip itself after which I get the job finished. Let me know if there are specific chips that need interfacing such as the RTCs and Bluetooth etc.
    RTC: DS3231(used in Chronodot)
    Bluetooth: RN-42 http://www.parallax.com/StoreSearchResults/tabid/768/txtSearch/Rn-42/List/0/SortField/4/ProductID/890/Default.aspx

    Getting an Asus TF300T tomorrow. Any tips on using the RN-42 with Blueterm?
  • bmentinkbmentink Posts: 107
    edited 2013-07-24 13:08
    There's the PWM code that's built in for 8 channels although it's a fairly easy matter to make it 32 channels so that you can choose arbitrary pins to suit. There's also the DAC function which could just as easily have a VOLTS function frontend to make it easier to set a voltage. So besides these and the frequency generation words that you can play with I think that it's easy enough to go to the next step of measuring etc. Have you had a look at the Introduction page? If you have something specific in mind I can work on that.

    Hmmm, been looking at the PWM code ... very confused. Code is:
                            org        _RUNMOD
    _PWM                        mov        deltaR,tos        ' use supplied delta value from tos
                             mov        target,tos
                            add        target,cnt
                            mov        R1,#0
    pwmlp                        mov        X,REG0        ' read base address of table
                            add        X,R1        ' add in read index
                             rdbyte        X,X
                             shl        X,REG1        ' shift up to pwmpins
                            mov        outa,X        ' update outputs
                            add        R1,#1
                            and        R1,#$FF
                            waitcnt        target,deltaR
                            jmp        #pwmlp
    PWM        byte        _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,13,XOP,xLOADMOD,EXIT
    

    It seems to me that your only using the cog timer for a delay right? all io is bit-bashed rather than using outa,outb?
    Also, I don't see how the above loop ends ... and ther is no jump to next or drop at the end of the code ... where does it go to?
    Seems I am missing a big chunk of information here ... also "org _RUNMOD" confuses me as it is used above each PASM code module, doesn't that mean they will all be assembled at the same place in memory?
    My head hurts..... :(

    EDIT: Why is the code I post all mashed up ... tried copy/pasting through different editors but still rubbish ..


    Bernie
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-24 15:29
    bmentink wrote: »
    Hmmm, been looking at the PWM code ... very confused. Code is:
                            org        _RUNMOD
    _PWM                        mov        deltaR,tos        ' use supplied delta value from tos
                             mov        target,tos
                            add        target,cnt
                            mov        R1,#0
    pwmlp                        mov        X,REG0        ' read base address of table
                            add        X,R1        ' add in read index
                             rdbyte        X,X
                             shl        X,REG1        ' shift up to pwmpins
                            mov        outa,X        ' update outputs
                            add        R1,#1
                            and        R1,#$FF
                            waitcnt        target,deltaR
                            jmp        #pwmlp
    PWM        byte        _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,13,XOP,xLOADMOD,EXIT
    

    It seems to me that your only using the cog timer for a delay right? all io is bit-bashed rather than using outa,outb?
    Also, I don't see how the above loop ends ... and ther is no jump to next or drop at the end of the code ... where does it go to?
    Seems I am missing a big chunk of information here ... also "org _RUNMOD" confuses me as it is used above each PASM code module, doesn't that mean they will all be assembled at the same place in memory?
    My head hurts..... :(

    EDIT: Why is the code I post all mashed up ... tried copy/pasting through different editors but still rubbish ..


    Bernie

    COG memory is very limited and Tachyon squeezes the VM and stacks in there and there's no room really left over for specialized operations that really require PASM. That's where RUNMOD comes in as I sacrifice 16 to 24 longs for specialized modules which are compiled to run at that address but only one module can be loaded at a time. These specialized modules include SPI, I2C, SD, and PWM etc. The PWM module is designed to run in it's own cog as it's an endless loop where another cog/task can control the parameters. Of course the PWM cog doesn't need all the Tachyon VM in it after that but it's easy to load the module in the normal fashion.

    So PWM doesn't use the counters, only WAITCNT but you mentioned PWM in your list which is different to duty-cycle modulation ( fixed pulse width, variable frequency).

    As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-24 16:14
    RTC: DS3231(used in Chronodot)
    Bluetooth: RN-42 http://www.parallax.com/StoreSearchResults/tabid/768/txtSearch/Rn-42/List/0/SortField/4/ProductID/890/Default.aspx

    Getting an Asus TF300T tomorrow. Any tips on using the RN-42 with Blueterm?

    The DS3231 is compatible enough with the MCP79410 that you should be able to use it as is, just change the device address. The first 7 registers are compatible although the 79410 does uses some of the otherwise unused bits for control purposes but that won't affect the 3231. Try it and let me know how is goes.

    The device address can be changed either in the source code:
    $DE == @rtc
    to

    $B0 == @rtc

    Or you can write directly to the constant at runtime with:
    $B0 ' @rtc 1+ !

    The RN42 should just work in slave mode and you should be able to change it's default baudrate to 230400.


  • D.PD.P Posts: 790
    edited 2013-07-24 17:17
    COG memory is very limited and Tachyon squeezes the VM and stacks in there ......

    As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.

    Now my head hurts because this wine is not available in the USA!

    Gonna have to place an Intl order
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-25 00:26
    I'm starting to get close to finishing the FAT32 file support, I've just been getting my head around where everything is and how it works by Googling bits of information and interacting with the code and card to check it all out. I know a FAT32 driver has been written but I haven't referenced it at all which may sound a bit odd seeing that the code is all there. The thing is I would have to get my head around the code and I'd much rather get my head around FAT32 and SDHC cards themselves, that way I can produce a nice clean interface and so far it's been working out that way. The code size is under 1.5K at present and probably will not increase too much more. Here's a capture of a quick session I did in mounting a card, checking the card info and performing a couple of operations on it and even accessing a file as virtual memory (me in red).
    [FONT=courier new][COLOR=#ff0000]MOUNT [/COLOR]
    655F_06B0: SYSLINUX  FAT32   
    Sectors = 7,725,056 ok
    [COLOR=#ff0000]SD [/COLOR]
    Card inserted 
    MFG                 27
    OEM                 PH
    Product ID          SD04G
    REV                 20
    S/N                 655F06B0
    DATE                2011/4
    CRC                 5B
      CSD REGISTER      
    *SDHC CARD* 
    TACC                100ns
    NSAC                0bps
    TRANS               50MHz
    BLKLEN              512
    SIZE                3,775 Mbytes
    ________________
     ok
    [COLOR=#ff0000]ls [/COLOR]
    UBNKERN .        UBNINIT .        UBNPATHL.TXT     AUTORUN .INF     MD5SUM  .TXT     UBNFILEL.TXT     LDLINUX .SYS     SYSLINUX.CFG 
    MENU    .C32      ok
    [COLOR=#ff0000]DIR [/COLOR]
    
    UBNKERN .    .....a 00004040    27/01/2012 20:44:04   4,658,096
    UBNINIT .    .....a 00006400    27/01/2012 20:44:06   20,068,855
    UBNPATHL.TXT .....a 0000FFC0    07/02/2012 11:37:06   87
    AUTORUN .INF .....a 00010140    09/11/2011 00:59:44   170
    MD5SUM  .TXT .....a 0024AE80    27/01/2012 20:49:54   12,511
    UBNFILEL.TXT .....a 0024AF40    07/02/2012 11:41:36   5,866
    LDLINUX .SYS rhs..a 0024AF80    07/02/2012 11:41:36   32,256
    SYSLINUX.CFG .....a 0024AFC0    07/02/2012 11:41:42   1,107
    MENU    .C32 .....a 0024B000    07/02/2012 11:41:42   56,164 ok
    [COLOR=#ff0000]cat AUTORUN.INF[/COLOR]...opened at 00010140
    [autorun]
    open=mint4win.exe --cdmenu --skipmd5check
    icon=mint4win.exe,0
    label=Install Linux Mint
    
    [Content]
    MusicFiles=false
    PictureFiles=false
    VideoFiles=false
      ok[/FONT]
    [COLOR=#ff0000]OPEN SYSLINUX.CFG[/COLOR]...opened at 0024AFC0  ok
    [COLOR=#ff0000]@FILE XADR 80 DUMP[/COLOR] 
    7600: 64 65 66 61 75 6C 74 20 6D 65 6E 75 2E 63 33 32    default menu.c32
    7610: 0A 70 72 6F 6D 70 74 20 30 0A 6D 65 6E 75 20 74    .prompt 0.menu t
    7620: 69 74 6C 65 20 55 4E 65 74 62 6F 6F 74 69 6E 0A    itle UNetbootin.
    7630: 74 69 6D 65 6F 75 74 20 31 30 30 0A 0A 6C 61 62    timeout 100..lab
    7640: 65 6C 20 75 6E 65 74 62 6F 6F 74 69 6E 64 65 66    el unetbootindef
    7650: 61 75 6C 74 0A 6D 65 6E 75 20 6C 61 62 65 6C 20    ault.menu label 
    7660: 44 65 66 61 75 6C 74 0A 6B 65 72 6E 65 6C 20 2F    Default.kernel /
    7670: 75 62 6E 6B 65 72 6E 0A 61 70 70 65 6E 64 20 69    ubnkern.append i
     ok
    
    
  • MJBMJB Posts: 1,235
    edited 2013-07-25 01:14
    since Peter was busy I continued my experiments and now I understand partly,
    why it could only work in this special case.
    I am revectoring KEY via ukey to read from a string.
    which can only work at the end of the input line, when the input loop comes back to calling KEY again.
    MJB wrote: »
    @Peter
    based on your new STRING words I wanted to build an EVAL
    which works - almost fine.

    BUT:
    1. maybe it would be better to suppress the echo of the evaluated string and show just the result
    (could be done using NULLOUT & CON see below )

    2. if used multiple times in one line or inside a loop, only the last EVAL seems to get executed.

    seems I still miss s.th. important
    \
    pub (EVALSTR) ( strAddr -- )
             C@++ DUP 0= IF DROP ukey W~ $0D THEN ;  ok
               ok
    
    pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
      ' (EVALSTR) ukey W! ;   ok
    
    { without output 
    pub (EVALSTR) ( strAddr -- )
             C@++ DUP 0= IF DROP CON $0D THEN ;   
              \ just deliver one char after the other, on last one add $0D to get it executed and set reader back to CONsole
    
    pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
        NULLOUT  \ suppress output 
        ' (EVALSTR) ukey W! ;  
    }
    
    " 1 1 + . " EVAL   ok
    1 1 + .  2 ok
    " 2 2 + . " EVAL   ok
    2 2 + .  4 ok
    
    " : TT1 $17 . ; " $20 STRING TESTSTR   ok
    TESTSTR EVAL  ok
    : TT1 $17 . ;   ok
    TT1 17 ok
      ok
    
    \ let's define a WORD, that generates other words ...  ( I worked many years with LISP ;-) - so I love EVAL )
    : TTT
    0 6 ADO  "0" I + TESTSTR 4 + C! "0" I + TESTSTR 8 + C! TESTSTR .STR CR TESTSTR [COLOR=#020FC0][B]EVAL [/B][/COLOR]LOOP
    ;  ok
      ok
    TTT : TT0 $10 . ;
    : TT1 $11 . ;
    : TT2 $12 . ;
    : TT3 $13 . ;
    : TT4 $14 . ;
    : TT5 $15 . ;
     ok
    : TT5 $15 . ;   ok
    

    so I tried the following modifications, which at least seem to work on the input line.
    But it is still not possible to put this inside a loop or definition of a word.
    in other words - I can not compile it.
    Since now I had to define EVAL as IMMEDIATE to work at least this far.
    pub (EVALSTR) ( strAddr -- )
             C@++ DUP 0= IF DROP CON  $0D  THEN   ;  
              \ just deliver one char after the other, on last one add $0D to get it executed and set reader back to CONsole
    
    pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
          [COMPILE] GRAB
        \  NULLOUT  \ suppress output
        ' (EVALSTR) ukey W! ; 
    IMMEDIATE    
    
        " 1 1 + . " EVAL  " 2 2 + . " EVAL  " 3 3  + . " EVAL 1 1 + 
    

    I assume I need to take a completely different approach for EVAL to do what I imagine.
  • D.PD.P Posts: 790
    edited 2013-07-25 10:52
    I'm starting to get close to finishing the FAT32 file support, I've just been getting my head around where everything is and how it works by Googling bits of information and interacting with the code and card to check it all out. I know a FAT32 driver has been written but I haven't referenced it at all which may sound a bit odd seeing that the code is all there. The thing is I would have to get my head around the code and I'd much rather get my head around FAT32 and SDHC cards themselves, that way I can produce a nice clean interface and so far it's been working out that way. The code size is under 1.5K at present and probably will not increase too much more. Here's a capture of a quick session I did in mounting a card, checking the card info and performing a couple of operations on it and even accessing a file as virtual memory (me in red).
    [FONT=courier new][COLOR=#ff0000]MOUNT [/COLOR]
    655F_06B0: SYSLINUX  FAT32   
    Sectors = 7,725,056 ok
    [COLOR=#ff0000]SD [/COLOR]
    Card inserted 
    MFG                 27
    OEM                 PH
    Product ID          SD04G
    REV                 20
    S/N                 655F06B0
    DATE                2011/4
    CRC                 5B
      CSD REGISTER      
    *SDHC CARD* 
    TACC                100ns
    NSAC                0bps
    TRANS               50MHz
    BLKLEN              512
    SIZE                3,775 Mbytes
    ________________
     ok
    [COLOR=#ff0000]ls [/COLOR]
    UBNKERN .        UBNINIT .        UBNPATHL.TXT     AUTORUN .INF     MD5SUM  .TXT     UBNFILEL.TXT     LDLINUX .SYS     SYSLINUX.CFG 
    MENU    .C32      ok
    [COLOR=#ff0000]DIR [/COLOR]
    
    UBNKERN .    .....a 00004040    27/01/2012 20:44:04   4,658,096
    UBNINIT .    .....a 00006400    27/01/2012 20:44:06   20,068,855
    UBNPATHL.TXT .....a 0000FFC0    07/02/2012 11:37:06   87
    AUTORUN .INF .....a 00010140    09/11/2011 00:59:44   170
    MD5SUM  .TXT .....a 0024AE80    27/01/2012 20:49:54   12,511
    UBNFILEL.TXT .....a 0024AF40    07/02/2012 11:41:36   5,866
    LDLINUX .SYS rhs..a 0024AF80    07/02/2012 11:41:36   32,256
    SYSLINUX.CFG .....a 0024AFC0    07/02/2012 11:41:42   1,107
    MENU    .C32 .....a 0024B000    07/02/2012 11:41:42   56,164 ok
    [COLOR=#ff0000]cat AUTORUN.INF[/COLOR]...opened at 00010140
    [autorun]
    open=mint4win.exe --cdmenu --skipmd5check
    icon=mint4win.exe,0
    label=Install Linux Mint
    
    [Content]
    MusicFiles=false
    PictureFiles=false
    VideoFiles=false
      ok[/FONT]
    [COLOR=#ff0000]OPEN SYSLINUX.CFG[/COLOR]...opened at 0024AFC0  ok
    [COLOR=#ff0000]@FILE XADR 80 DUMP[/COLOR] 
    7600: 64 65 66 61 75 6C 74 20 6D 65 6E 75 2E 63 33 32    default menu.c32
    7610: 0A 70 72 6F 6D 70 74 20 30 0A 6D 65 6E 75 20 74    .prompt 0.menu t
    7620: 69 74 6C 65 20 55 4E 65 74 62 6F 6F 74 69 6E 0A    itle UNetbootin.
    7630: 74 69 6D 65 6F 75 74 20 31 30 30 0A 0A 6C 61 62    timeout 100..lab
    7640: 65 6C 20 75 6E 65 74 62 6F 6F 74 69 6E 64 65 66    el unetbootindef
    7650: 61 75 6C 74 0A 6D 65 6E 75 20 6C 61 62 65 6C 20    ault.menu label 
    7660: 44 65 66 61 75 6C 74 0A 6B 65 72 6E 65 6C 20 2F    Default.kernel /
    7670: 75 62 6E 6B 65 72 6E 0A 61 70 70 65 6E 64 20 69    ubnkern.append i
     ok
    
    

    Can't wait but I will.

    Perfect for logging, writing and running profiles for my Tachyon/Forth machine.

    Will this be available in V2.1? or 3.x only?

    Pre thanks Peter.
  • bmentinkbmentink Posts: 107
    edited 2013-07-25 13:18
    COG memory is very limited and Tachyon squeezes the VM and stacks in there and there's no room really left over for specialized operations that really require PASM. That's where RUNMOD comes in as I sacrifice 16 to 24 longs for specialized modules which are compiled to run at that address but only one module can be loaded at a time. These specialized modules include SPI, I2C, SD, and PWM etc. The PWM module is designed to run in it's own cog as it's an endless loop where another cog/task can control the parameters. Of course the PWM cog doesn't need all the Tachyon VM in it after that but it's easy to load the module in the normal fashion.

    So PWM doesn't use the counters, only WAITCNT but you mentioned PWM in your list which is different to duty-cycle modulation ( fixed pulse width, variable frequency).

    As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.

    Will do ... although I had to replace the Pepperjack with a Local Merlot ..... distinct lack of Oz wines over here .... ;)

    By the way, what I am trying to do is this:

    My interest is Electric Cars ... currently I am building one based on a 200HP Industrial motor running at 650V. (Biggest problem is the cost of the controller ... even when I got the power module off eBay)
    That is all good, but for my next project I would like to use a BLDC motor being driven by a Prop1 (in sensorless mode) or maybe a Prop2 if I run out of resources .... seems to me I can get the cost of the controller right down ...

    So I would like to start the coding based on the Prop1 and see how far I get ... and obviously I would like to do this in Tachyon Forth .. :)

    .... So I am thinking for the 3 Phase PWM, maybe I could use 3 cogs running a low level PWM word that could be phase shifted relative to each other .... (using timers)
    Another cog would interface to the sensorless circuitry (zero-crossing detector) and would self modify the phase shifting .. (phase shift is normally 60deg in a six step BLDC)
    Be interested in what you think of that approach and what the best words would be to achieve the building blocks ..

    NB: I have seen the 32 channel PWM code that Parallax have coded up to do this sort of thing in pure assembly, but surely we can use cog timers for this ....

    Cheers,
    Bernie
  • MJBMJB Posts: 1,235
    edited 2013-07-25 17:49
    circular byte buffers are a common data structure
    here my attempt at a generalization of it.
    comments and optimizations welcome.
     \ =============  BUFFER  ===========================
     \ usage  size BUFFER BufName 
    pub BUFFER ( size --  
        \ create a circular buffer of size bytes, 
        \ 4 bytes size, R-index, W-index and VAR byte code preceed buffer address )
        [COMPILE] GRAB   \ force evaluation auf previous input 
        3 ALLOT          \ space for  size, Rind, Wind 
        DUP HERE 3 - C!      \ store buffer length
        HERE 2- C~       \ make sure it is 0 - maybe not needed
        HERE 1- C~       \ make sure it is 0 
        [COMPILE] CREATE   \ create a variable which returns the buffer start address
        ALLOT              \ allocate size bytes needed which are automatically 0 ??
        ;
    IMMEDIATE
    
    pub BUFEMPTY ( bufAddr -- flag ) DUP 3 - C@ SWAP 2- C@ = ;
    {
    #10 BUFFER mBuf
    mBuf 5 - 20 DUMP
    mBuf BUFEMPTY .
    }
    pub BUFSIZE ( bufAddr -- size ) 4 - C@ ;
    {
    mBuf BUFSIZE .
    }
    pri BUFR ( bufAddr -- rIndex ) 3 -  ;   \ address of buffer read index
    pri BUFW ( bufAddr -- wIndex ) 2-  ;    \ address of buffer write index
    {
    mBuf BUFR .
    mBuf BUFW .
    }
    pri BUFR@ ( bufAddr -- rIndex )  BUFR C@  ;       \  value of buffer read index
    pri BUFR@@ ( bufAddr -- rByte ) DUP BUFR@ + C@ ; \  byte of buffer at read index
    pri BUFW@ ( bufAddr -- wIndex )  BUFW C@ ;        \  value of buffer write index
    pri BUFW@! ( wByte bufAddr --  ) DUP BUFW@ + C! ; \  store byte to buffer at write index  
    {
    mBuf BUFR@ .
    mBuf BUFW@ .
    12 mBuf BUFW@!    mBuf 4 - 20 DUMP
    }
    pub BUFFREE ( bufAddr -- flag ) 
        DUP BUFSIZE  ( bufAddr size )
        OVER BUFW -   ( bufAddr size-wPtr )
        SWAP BUFR +     
        ;
    {
    mBuf BUFFREE .
    }
    pub BUFFULL ( bufAddr -- flag ) BUFFREE 0= ;
    {
    mBuf BUFFULL .
    } 
    pub BUFRD ( bufAddr -- byte ) 
        DUP BUFR@@ SWAP  ( byte bufAddr ) \ get the value at buffer read pos 
        DUP BUFR C++
        DUP BUFR@ OVER    ( byte bufAddr rIndex bufAddr ) 
        BUFSIZE =  IF BUFR C~ ELSE DROP THEN   
        ;
        
    pub BUFWR ( byte bufAddr --  ) 
        SWAP OVER  BUFW@!   ( bufAddr ) \ write the value to buffer at write pos 
        DUP BUFW C++ 
        DUP BUFW@ OVER    ( bufAddr wIndex bufAddr ) 
        BUFSIZE =  IF BUFW C~ ELSE DROP THEN   
        ;
    {    
    1 mBuf BUFWR
    2 mBuf BUFWR
    mBuf 4 - 20 DUMP
    mBuf BUFRD .
    mBuf BUFRD .
    
    1 5 ADO I mBuf BUFWR LOOP 
    mBuf 4 - 20 DUMP
    3 mBuf BUFWR mBuf 4 - 20 DUMP
    4 mBuf BUFWR mBuf 4 - 20 DUMP
    5 mBuf BUFWR mBuf 4 - 20 DUMP
    6 mBuf BUFWR mBuf 4 - 20 DUMP
    17 mBuf BUFWR mBuf 4 - 20 DUMP
    17 mBuf BUFWR mBuf 4 - 20 DUMP
    }    
    pub BUFCLR ( bufAddr -- ) \ clear buffer 
        DUP BUFR C~
        DUP BUFW C~
        DUP BUFSIZE ERASE ;
    {    
    mBuf 4 - 20 DUMP    
    mBuf BUFCLR
    mBuf 4 - 20 DUMP
    }
    pub BUFCNT ( bufAddr -- count ) 
        DUP BUFSIZE  ( bufAddr size )
        SWAP BUFFREE -
        ;
    {
    mBuf BUFFREE . 
    mBuf BUFCNT .
    }
        
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-25 21:26
    bmentink wrote: »
    Will do ... although I had to replace the Pepperjack with a Local Merlot ..... distinct lack of Oz wines over here .... ;)

    By the way, what I am trying to do is this:

    My interest is Electric Cars ... currently I am building one based on a 200HP Industrial motor running at 650V. (Biggest problem is the cost of the controller ... even when I got the power module off eBay)
    That is all good, but for my next project I would like to use a BLDC motor being driven by a Prop1 (in sensorless mode) or maybe a Prop2 if I run out of resources .... seems to me I can get the cost of the controller right down ...

    So I would like to start the coding based on the Prop1 and see how far I get ... and obviously I would like to do this in Tachyon Forth .. :)

    .... So I am thinking for the 3 Phase PWM, maybe I could use 3 cogs running a low level PWM word that could be phase shifted relative to each other .... (using timers)
    Another cog would interface to the sensorless circuitry (zero-crossing detector) and would self modify the phase shifting .. (phase shift is normally 60deg in a six step BLDC)
    Be interested in what you think of that approach and what the best words would be to achieve the building blocks ..

    NB: I have seen the 32 channel PWM code that Parallax have coded up to do this sort of thing in pure assembly, but surely we can use cog timers for this ....

    Cheers,
    Bernie

    I can't see how a 32 channel PWM could be implemented by counters or even without a cog involved. It could be possible to use the video register though for 8 channels and I'm not sure if that's been done yet but it would still need a cog dedicated to it. The present PWM runs 8-bit PWM up to around 5kHz which means it's updating every 781ns as it needs to read from a table in hub ram (slow) which can be updated by another cog. Sure you could place the table in COG RAM but how do you change it without upsetting the PWM updates? I could update the 8-bit method to read in a long each time if I want to speed it up but I'd have to time the hub access to make sure it's synchronized too.

    Remember the Prop design philosopy, the cog is the peripheral, you don't have UARTs, SPI, I2C, ADC, DAC, DMA, VGA, A/V, PWM etc hardwired in, but each cog can do just that. Although each cog is a CPU, it's not necessarily THE CENTRAL processing unit and unlike prima donnas they are humble and flexible enough to be what they need to be ("be a radio"! Okay!)

    BTW, Pepperjack is a very lovely red for sure but it's kinda like my baseline red :) Life is too short to drink cheap wine I say!
  • bmentinkbmentink Posts: 107
    edited 2013-07-26 15:59
    I can't see how a 32 channel PWM could be implemented by counters or even without a cog involved. It could be possible to use the video register though for 8 channels and I'm not sure if that's been done yet but it would still need a cog dedicated to it. The present PWM runs 8-bit PWM up to around 5kHz which means it's updating every 781ns as it needs to read from a table in hub ram (slow) which can be updated by another cog. Sure you could place the table in COG RAM but how do you change it without upsetting the PWM updates? I could update the 8-bit method to read in a long each time if I want to speed it up but I'd have to time the hub access to make sure it's synchronized too.

    Remember the Prop design philosopy, the cog is the peripheral, you don't have UARTs, SPI, I2C, ADC, DAC, DMA, VGA, A/V, PWM etc hardwired in, but each cog can do just that. Although each cog is a CPU, it's not necessarily THE CENTRAL processing unit and unlike prima donnas they are humble and flexible enough to be what they need to be ("be a radio"! Okay!)

    BTW, Pepperjack is a very lovely red for sure but it's kinda like my baseline red :) Life is too short to drink cheap wine I say!

    No, I don't want or need 32 channels, just quoting some example code that was entirely bit bashed PASM code ...
    All I need is 3Phase PWM that is gated by the commutation circuitry ..I was thinking of using a cog each for the 3 PWM, and stopping/starting cogs to gate them ..not sure if this is the best approach.

    As you know BLDC is usually a six step waveform across the 3 phases, 60deg apart, and each step could be either a duty cycle controlled PWM of fully on or fully off. The commutation determines when the start of these steps happens.

    So there will be 6 (3 complementary ) outputs (timers in PWM mode) and three inputs .... the three inputs really need to go through a comparator , which for the P1 looks like I will need external ones, looks like the P2 could do this with it's comparator on each pin.

    So, I am going to build some interface circuitry on the Prop Proto board and would like to play around with some interfacing code and the PWM stuff ..
    As far as the current PWM word, I may have some suggestions to modify it to allow gating ... that would help my application .. (instead of Cog on/off stuff)

    Thanks,
    Bernie
  • MJBMJB Posts: 1,235
    edited 2013-07-27 00:30
    bmentink wrote: »
    No, I don't want or need 32 channels, just quoting some example code that was entirely bit bashed PASM code ...
    All I need is 3Phase PWM that is gated by the commutation circuitry ..I was thinking of using a cog each for the 3 PWM, and stopping/starting cogs to gate them ..not sure if this is the best approach.

    As you know BLDC is usually a six step waveform across the 3 phases, 60deg apart, and each step could be either a duty cycle controlled PWM of fully on or fully off. The commutation determines when the start of these steps happens.

    So there will be 6 (3 complementary ) outputs (timers in PWM mode) and three inputs .... the three inputs really need to go through a comparator , which for the P1 looks like I will need external ones, looks like the P2 could do this with it's comparator on each pin.

    So, I am going to build some interface circuitry on the Prop Proto board and would like to play around with some interfacing code and the PWM stuff ..
    As far as the current PWM word, I may have some suggestions to modify it to allow gating ... that would help my application .. (instead of Cog on/off stuff)

    Thanks,
    Bernie
    for the table driven PWM code Peter gives:
    This version is set to run up to 8 channels of 8-bit PWM at 1kHz (Tested to 5kHz)
    so this would work for a slow motor
    and as you write, COG on/off is slow and not a good option.
    Updating the PWM tables even in tha PASM version takes
    New kernel module method to speed-up updates = 233us total
    which gives you a 4kHz update rate - if this is fast enough depends on your motor dynamics.

    At what RPM do you run?

    Adding gating to the PWM-Code module inside the Tachyon core shouldn't be to difficult.
    org        _RUNMOD
    _PWM                        mov        deltaR,tos        ' use supplied delta value from tos
                             mov        target,tos
                            add        target,cnt
                            mov        R1,#0
    pwmlp              
    
                            mov        X,REG0        ' read base address of table
                            add        X,R1        ' add in read index
                             rdbyte        X,X
    [SIZE=3][B]' here you can read and check a HUB variable with a gate MASK
                      rdbyte     R2,REG3     ' use e.g. REG3 to hold the gate mask HUB address for all 8 channels
                      and       X,R2[/B][/SIZE]                  ' [B][SIZE=3]mask the PWM [/SIZE][/B]- depending on positive or negative logic might need to be inverted
                             shl        X,REG1        ' shift up to pwmpins
                            mov        outa,X        ' update outputs
                            add        R1,#1
                            and        R1,#$FF
    pwmwait          waitcnt        target,deltaR
                            jmp        #pwmlp
    
    PWM        byte        _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,1[SIZE=5][B]5[/B][/SIZE],XOP,xLOADMOD,EXIT    ' adapt PASM line count
    
  • MJBMJB Posts: 1,235
    edited 2013-07-27 01:24
    It took me quite some time to figure out, what STRING is really doing.
    So I commented the code - hope it is right.
    If not please correct somebody / Peter ...
    \ commented by Markus Baer MJB ( for my understanding - hope this is correct )
    pub STRING ( str max -- )                            \ Specify max size of string else use 0 for string length
            [COMPILE] GRAB                              \ execute input before STRING                   
            ?DUP 0= IF DUP STRLEN 1+ THEN SWAP   ( max str )    \ max is STRLEN+1 if max given was 0 
            codes W@ 4 ALIGN codes W! ALLOCATED ( size str )       \ make long aligned, adjust here
    ( since the string literal is in the place where we want to create the STRING variable, we need to save the string somewhere further up in the buffer.
    CREATE not only compiles the VARB byte code, but also appends an EXIT 
    because of this we can not move the string const to the final place yet,
    but we need to move up 1 char more )
            HERE 5 + OVER STRLEN 1+ <CMOVE   \  move out of the way
             $80 HERE C!                                          \ set the attribute byte, first byte of the STRING header
             DUP HERE 1+ C!                                    \ store the size in the second byte of STRING header
             HERE 4 + STRLEN HERE 2+ C!             \ calc the null terminated string len and store it in third byte of STRING header
            3 ALLOT                                                 \ allocate space for the 3 header bytes, adjust here
            [COMPILE] CREATE                               \ since CREATE is immediate we need to prefix with [COMPILE]
                                                                           \ CREATE creates a variable, that returns its address to TOS
    ( now we need to move the string literal value to the right position replacing the EXIT byte code compiled in by CREATE, which we don't need  )    
            HERE 1+ DUP STRLEN 1+ OVER 1- SWAP CMOVE     
    ( now move the here pointer to the end of the string by allocating the requested length or if this was 0 then the length of the string const plus the 0 end byte.
            HERE 3 - C@ ALLOT
            ; 
    IMMEDIATE    \ make this an immediate so the STRING is created direcly
    
    
    reverse engineering Peter's code raises my insight, and I hope, TACHYON 3.0 will not be too different inside and I have to relearn all again ...

    sorry - I just can't get the comments aligned correctly
  • bmentinkbmentink Posts: 107
    edited 2013-07-27 01:31
    MJB wrote: »
    for the table driven PWM code Peter gives:

    so this would work for a slow motor
    and as you write, COG on/off is slow and not a good option.
    Updating the PWM tables even in tha PASM version takes

    which gives you a 4kHz update rate - if this is fast enough depends on your motor dynamics.

    At what RPM do you run?

    Adding gating to the PWM-Code module inside the Tachyon core shouldn't be to difficult.
    org        _RUNMOD
    _PWM                        mov        deltaR,tos        ' use supplied delta value from tos
                             mov        target,tos
                            add        target,cnt
                            mov        R1,#0
    pwmlp              
    
                            mov        X,REG0        ' read base address of table
                            add        X,R1        ' add in read index
                             rdbyte        X,X
    [SIZE=3][B]' here you can read and check a HUB variable with a gate MASK
                      rdbyte     R2,REG3     ' use e.g. REG3 to hold the gate mask HUB address for all 8 channels
                      and       X,R2[/B][/SIZE]                  ' [B][SIZE=3]mask the PWM [/SIZE][/B]- depending on positive or negative logic might need to be inverted
                             shl        X,REG1        ' shift up to pwmpins
                            mov        outa,X        ' update outputs
                            add        R1,#1
                            and        R1,#$FF
    pwmwait          waitcnt        target,deltaR
                            jmp        #pwmlp
    
    PWM        byte        _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,1[SIZE=5][B]5[/B][/SIZE],XOP,xLOADMOD,EXIT    ' adapt PASM line count
    

    Hi MJB,

    Thanks. I do actually need much faster PWM ... in the order of 10..15Khz, which is why I was wondering about using the Cog timers in PWM mode with complementary outputs and gating those some how,
    rather than doing bit-bashing as per Peter's code ..

    My other requirement is to have a cog act as a re-triggerable mono-stable as part of the commutation side ... I wonder if that can also be done using a Cog timer.

    B.
  • MJBMJB Posts: 1,235
    edited 2013-07-27 15:16
    bmentink wrote: »
    Hi MJB,

    Thanks. I do actually need much faster PWM ... in the order of 10..15Khz, which is why I was wondering about using the Cog timers in PWM mode with complementary outputs and gating those some how,
    rather than doing bit-bashing as per Peter's code ..

    a very simple method for gating would be setting the pins to inputs with pullup or pull downs as appropriate, while the counter-PWM continues
    My other requirement is to have a cog act as a re-triggerable mono-stable as part of the commutation side ... I wonder if that can also be done using a Cog timer.

    B.
    you can easily implement a SW monoflop - if timing is sufficient.

    I use a COG to implement a legacy bus interface - kind a SW CPLD.
    Reaction is 25 .. 50 ns for the most time critical transition.
  • bmentinkbmentink Posts: 107
    edited 2013-07-28 01:20
    MJB wrote: »
    a very simple method for gating would be setting the pins to inputs with pullup or pull downs as appropriate, while the counter-PWM continues

    I don't think that would work, I need to turn those outputs on or off when they are not PWM outputs. I wonder about changing the pwm mode in a way that they go high or low?
    you can easily implement a SW monoflop - if timing is sufficient.

    Can you elaborate with some Pseudo code on how that would work?

    Thanks,
    B.
  • kuronekokuroneko Posts: 3,623
    edited 2013-07-28 01:32
    @bmentink: would something like http://obex.parallax.com/object/482 work for you (3ctrx variant)? It may need some work but everything is done inside the prop (there is at least one other implementation available).
  • MJBMJB Posts: 1,235
    edited 2013-07-28 02:28
    bmentink wrote: »
    Can you elaborate with some Pseudo code on how that would work?
    B.
    a monoflop is very simple.
    e.g.:
    output is low
    trigger
    set output high
    set timer variable / manual countdown counter with value for impuls time
    looplabel
    ... on retrigger event reload counter variable with original value ...
    djnz looplabel
    set output low


    using waitcnt will not work, since there must be s.th. to check for retrigger signal
    so you can just use a simple tight polling loop.
    I don't see how counters could be used for this.
  • MJBMJB Posts: 1,235
    edited 2013-07-28 02:45
    kuroneko wrote: »
    @bmentink: would something like http://obex.parallax.com/object/482 work for you (3ctrx variant)? It may need some work but everything is done inside the prop (there is at least one other implementation available).

    there are some more:
    http://obex.parallax.com/object/211 (looks slow)
    search OBEX for PWM or MOTOR

    an interresting question might be:
    Is PWM really needed to drive the motor - or would duty mode be useful as well?
    It can be easily generated with the counters.
    the important feature is to generate the appropriate average current within the time interval.
    Inductivity averages it - so I wonder if the exact phase of PWM is a must have. ...???
  • bmentinkbmentink Posts: 107
    edited 2013-07-28 22:34
    MJB wrote: »
    a monoflop is very simple.
    e.g.:
    output is low
    trigger
    set output high
    set timer variable / manual countdown counter with value for impuls time
    looplabel
    ... on retrigger event reload counter variable with original value ...
    djnz looplabel
    set output low


    using waitcnt will not work, since there must be s.th. to check for retrigger signal
    so you can just use a simple tight polling loop.
    I don't see how counters could be used for this.

    Thanks, that makes sense .. I could not work out how it could work with a cog counter either ..
    I need three of these, so guess I could use one cog to do all three in PASM as above ..
    an interresting question might be:
    Is PWM really needed to drive the motor - or would duty mode be useful as well?
    It can be easily generated with the counters.
    the important feature is to generate the appropriate average current within the time interval.
    Inductivity averages it - so I wonder if the exact phase of PWM is a must have. ...???

    I think PWM is needed as duty mode would give some interesting motor noises as you sped up and down due to motor resonances .. I think you do need a constant frequency.
    I though PWM mode (NCO mode) generated a constant frequency, with variable duty .... am I wrong?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-28 22:59
    bmentink wrote: »
    Thanks, that makes sense .. I could not work out how it could work with a cog counter either ..
    I need three of these, so guess I could use one cog to do all three in PASM as above ..



    I think PWM is needed as duty mode would give some interesting motor noises as you sped up and down due to motor resonances .. I think you do need a constant frequency.
    I though PWM mode (NCO mode) generated a constant frequency, with variable duty .... am I wrong?

    Bernie, if you want to see what the different modes do then hook-up a scope and sit at the terminal and try the modes. It's very simple and all the words are there (in EXTEND.fth) to allow you to change things easily and of course interactively.
  • bmentinkbmentink Posts: 107
    edited 2013-07-29 00:56
    Hi Peter,

    Yes of course I will do that ... just someone has stolen my Prop board for that express purpose ... to play with Forth ( a new convert) ... so I am giving him some head ..
    When I get the board back I will be into it ... just thought I could get a quick answer back wile i wait .. ;)
  • Brian RileyBrian Riley Posts: 626
    edited 2013-07-29 15:13
    Peter et al.,

    I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?

    TNX in advance .... cheers ... BBR
  • MJBMJB Posts: 1,235
    edited 2013-07-29 15:41
    Peter et al.,

    I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?

    TNX in advance .... cheers ... BBR
    \ Adjust and dump the current Tachyon binary image in Intel hex format for conversion at the PC end to a bin file

    \ The bin file should be renamed as .binary to suit the Prop tool

    pub BINARYDUMP

    0 $7FE0

    2DUP FIXCKSUM

    IDUMP

    ;
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-29 15:43
    Peter et al.,

    I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?

    TNX in advance .... cheers ... BBR

    The BINARYDUMP word will dump the whole 32K less the top 32 bytes in Intel hex format with the correct Spin header checksum so you can run a HEX2BIN or equivalent on the PC end. Just make sure that the binary is named with the .binary extension so the Prop tool can handle it.
  • Brian RileyBrian Riley Posts: 626
    edited 2013-07-30 14:19
    BINARYDUMP worked fine for me ... tnx Peter.

    The discussions on i/o redirection came to me today as I was editing my BBR_Extensions.fth file for the umpteenth time ... and I wondered if I could apply our ever-so-slippery "variable constant" technique to the same end result ...
    #P15	CONSTANT	#SO	 \ declare #SO and set default
    
    : SO!	( serpin -- )	' #SO 1+ ! ;
    
    :	LCDEMIT		#19200 SERBAUD  #SO SEROUT ;
    :	LCD			' LCDEMIT uemit W! ;
    

    I typed
    #P2  SO!  "   HELLO WORLD" .LSTR
    
    .... it worked ... the serial LCD on Pin2 displayed the string (.LSTR word invokes LCD does a string print and returns the CONsole)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-07-30 18:03
    BINARYDUMP worked fine for me ... tnx Peter.

    The discussions on i/o redirection came to me today as I was editing my BBR_Extensions.fth file for the umpteenth time ... and I wondered if I could apply our ever-so-slippery "variable constant" technique to the same end result ...
    #P15    CONSTANT    #SO     \ declare #SO and set default
    
    : SO!    ( serpin -- )    ' #SO 1+ ! ;
    
    :    LCDEMIT        #19200 SERBAUD  #SO SEROUT ;
    :    LCD            ' LCDEMIT uemit W! ;
    

    I typed
    #P2  SO!  "   HELLO WORLD" .LSTR
    
    .... it worked ... the serial LCD on Pin2 displayed the string (.LSTR word invokes LCD does a string print and returns the CONsole)

    Hi Brian,
    I'm scrathing my head as to why it is done this way which looks awkward plus I'm not sure what .LSTR does that's different from the normal ." word or even the .STR or TYPE$ words. However I don't really see the need for redirection unless I had multiple serial displays and that would be easy enough too. The rewritable constant is actually redundant if you see how I would handle a couple of different serial devices using SEROUT:
    [SIZE=3][FONT=courier new]: LCDEMIT        #P2 SEROUT ;
    \ Set baudrate for the LCD and select the txd pin used
    : LCD            ' LCDEMIT uemit W! #19200 SERBAUD ;
    
    : TTYEMIT        #P7 SEROUT ;
    : TELETYPE        ' TTYEMIT uemit W! #300 SERBAUD ;
    
    \ Test out these words
    LCD ." HELLO WORLD" CON
    
    TELETYPE ." HELLO WORLD, THIS IS " .VER CON[/FONT][/SIZE]
    

    It's also more desirable to set the baudrate once when the output device is selected as baudrate is a redundant and time-consuming calculation that ends up repeating for every character that's sent.
    If I had multiple LCDs I might add a parameter to LCD and invoke it like this:
    #P2 LCD ." HELLO WORLD" #P7 LCD ." HELLO WORLD FROM ME TOO" CON

    There's even this version of the LCD and TELETYPE snippet that uses a common output word that uses a variable to hold the pin.
    [SIZE=3][FONT=courier new]
    BYTE serout
    : SEROUT2        serout C@ SEROUT ;
    \ Set baudrate for the LCD and select the txd pin used
    : LCD            ' SEROUT2 uemit W! #19200 SERBAUD #P2 serout C! ;
    
    : TELETYPE        ' SEROUT2 uemit W! #300 SERBAUD #P7 serout C! ;[/FONT][/SIZE]
    
Sign In or Register to comment.