Shop Learn
Propeller GUI touchscreen and full color display - Page 19 — Parallax Forums

Propeller GUI touchscreen and full color display



  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-04 01:12
    Sounds good. I won't get a chance to look at code for a few days - real work getting in the way :)

    Re testing, yes I have found every time I do a big change, I have to go and recompile all the apps and make sure they are all still working.

    Re "EXCEPT for initial development where program will most likely be run from unknown state."

    For that, what I am doing is putting the desktop program in eeprom and debug a new app in ram with F10 downloads. Then the initial state is known because the eeprom program will have written the type of display out to external ram. Actually, if it is done that way, it does not really matter that all the initialisation code is in inefficient spin because there is plenty of space in the desktop program, and the apps don't need to reinitialise the displays. So it is just the draw routine we need to move into spin. That simplifies things a bit.

    Nice about 227 longs left. Maybe there is indeed room left for a cache driver too?
  • average joeaverage joe Posts: 795
    edited 2012-09-04 16:28
    I'm still finishing homework for the week so time is limited still. I did take another stab at the cache driver and I'm STILL doing something wrong. It passes the cache test, but won't run in XMMC model yet. I've been going through the previous thread in the GCC forum and might have something. More on that later.

    I'm fairly sure touch.spin v0.8.6 is stable. I've also been working on a bug in the buttons program. I've decided that my 3am "fix" of swapping true and false is the wrong way and will be changing the bmp. I'll upload project later today. There's also some bugs in keyboard.. I'll work on those later.

    204 longs left in the cache driver *although it doesn't seem to work?* so there should be room for current PASM to port to C. Need to get the cache driver working FIRST!

    I have desktop loaded into EEPROM but for some reason... When using the programming method you described, the programs don't seem to return to desktop properly. Runs fine compiled to SD though.

    Draw in PASM could be optimized further, and I will work on it some more. My idea is to use hub2display loop, since the same code is currently repeated 3 times. Just wanted to get it working first, and it does. The other optimization might not seem big, but I feel removing the if "s", if "I" from the spin code will help speeds more. I think the previous example of what I'd like to be doing in spin will work. Just need to "nail down" the PASM.

    Expansion boards arrived today! I'll solder one up next week, need to get some new resistors for the Vdacs!

    I think I figured the reset bug out... Still trying to understand a whole strip *25* 33k's measuring around 90k? They're old *maybe 5 yrs.* from the shack. Been in the 'spare passives' box for a while, but nothing to indicate fault. Guess I should be double checking all resistors from now on. Have not tried a different resistor yet since I pulled the SubD connector already. When parts arrive, *futurlec is taking their time as always* I'll continue soldering boards up.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-04 17:21
    I *still* can't quite articulate the problem with the cache but I have this gut feeling that it won't work. I think what you need is to bundle a sd file open, data transfer and file close into one cache block, so that then you can be definite that there will be no cache refreshes during the transfer of a file. It involves getting deeper inside the C code and really understanding all the drivers. I can't see a way of doing that apart from taking Kye's code, reordering the functions and running it through the Spin2C program. But I don't fully understand how the C code is working inside - is there any spin anywhere or is it C code under the hood as well? I don't think I have enough information to say whether C can run on this board as well as Spin does.

    re your resistors - that is very odd for a 33k to measure 90k. I have never seen a resistor read wrong. However, I have seen my multimeter read wrong when the battery is going flat. I now have two multimeters and if I get an odd reading I check on the other one.

    On the other hand, if indeed it is 90k, then that would upset the RC timing and could well account for your reset bug.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-05 06:30
    I've spent some time moving the draw routine into pasm. It ended up being two routines, one for each display. It certainly is faster with the lorem program, and it is a lot faster with the pacman program as this is drawing lots of little tiles. Included is the new touch.spin and also pacman.spin and the bitmaps this uses. Draws the screen and moves a ghost around at the moment.

    It can go faster again - at the moment it is restarting a few things each draw routine and I am sure that they can go but lorem keeps breaking between characters if there is a call to spinhubtoram.

    In a general sense, putting draw into pasm speeds up text and it speeds up games because both of those have small tile sizes.

    I tested it with both displays. I probably need to go through what changes you would like to make.
    ' ********** command D and G draw subroutines in pasm **************
    pasm_RS_Low             and     latchvalue,#%01111111                           ' RS low
                            call    #set373
    pasm_RS_Low_ret         ret
    pasm_RS_High            or      latchvalue,#%10000000                           ' RS high
                            call    #set373
    pasm_RS_High_ret        ret
    pasm_send               andn    outa,maskP19            ' CS low
                            and     outa,maskP16P31         ' %11111111_11111111_00000000_00000000        ' set P0-P15 to zero ready to OR   
                            or      outa,data_16            ' send out the data
                            andn    outa,maskP18            ' ILI write low
                            or      outa,maskP18            ' ILI write high
                            or      outa,maskP19            ' CS high
    pasm_send_ret           ret                        
    pasm_Lcd_Write_Com                                      ' pass data_16
                            call    #pasm_RS_Low            ' RS low
                            call    #pasm_send
    pasm_Lcd_Write_Com_ret  ret                             ' return
    pasm_Lcd_Write_Data                                     ' pass data_16
                            call    #pasm_RS_High           ' RS high
                            call    #pasm_send
    pasm_Lcd_Write_Data_ret ret                             ' return
    pasm_draw_cmd           call    #pasm_Lcd_Write_Com     ' send out
                            rdword  data_16,hubaddr         ' get the word from hub
                            add     hubaddr,#2              ' get x1 etc
                            call    #pasm_Lcd_Write_Data
    pasm_draw_cmd_ret       ret
    pasm_draw_start         or      dira,maskP0P15          ' %00000000_00000000_11111111_11111111
                            or      latchvalue,#%00001111
                            and     latchvalue,#%11111101    ' group 2    
                            call    #set373
    pasm_draw_start_ret     ret                       
    pasm_Draw_ILI9325       ' replicates the spin version, but assumes already in drawing mode as this is quicker
                            ' pass a list of words in hubaddr x1,y1,x2,y2
                            ' this is the ILI9325 version, the SSD1289 version is slightly different see below   
                            ' no orientation change, so suggest the first draw in a sequence is the pasm version as this sets orientation as well
                            ' block is $50,x1,$52,y1,$51,x2,$53,y2,$20,x1,$21,y1, then cmd $22
                            call    #pasm_draw_start        ' startup common commands with the SSD display
                            mov     data_16,#$50            ' command  0x50
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$52            ' command  0x52
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$51            ' command  0x51
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$53            ' command  0x53
                            call    #pasm_draw_cmd          ' send out
                            sub     hubaddr,#8              ' back to beginning = x1
                            mov     data_16,#$20            ' command  0x20
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$21            ' command  0x21
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$22            ' command  0x22
                            call    #pasm_Lcd_Write_Com     ' send out
                            call    #pasm_RS_High           ' finish with RS high
                            jmp     #init                   ' finished
    pasm_Draw_SSD1289       call    #pasm_draw_start
                            mov     data_16,#$44            ' command  0x44
                            call    #pasm_Lcd_Write_Com     ' send out
                            rdword  pasm_n,hubaddr          ' get the word from hub
                            add     hubaddr,#4              ' merge x2 and x1
                            rdword  data_16,hubaddr
                            shl     data_16,#8
                            or      data_16,pasm_n
                            call    #pasm_Lcd_Write_Data
                            sub     hubaddr,#2               ' point to y1
                            mov     data_16,#$45            ' command  0x45
                            call    #pasm_draw_cmd          ' send out
                            add     hubaddr,#2              ' point to y2
                            mov     data_16,#$46            ' command  0x46
                            call    #pasm_draw_cmd          ' send out y2
                            sub     hubaddr,#8              ' back to beginning = x1
                            mov     data_16,#$4E            ' command  0x4E
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$4F            ' command  0x4F
                            call    #pasm_draw_cmd          ' send out
                            mov     data_16,#$22            ' command  0x22
                            call    #pasm_Lcd_Write_Com     ' send out
                            call    #pasm_RS_High           ' finish with RS high
                            jmp     #init                   ' finished
  • average joeaverage joe Posts: 795
    edited 2012-09-05 08:53
    Very nice work! I think I was over-complicating things with self-modifying code, etc.. I would still like to get burst transfers working, and they appear to be... I still can not explain a couple of the instructions so need to think on this. I'm also curious about your thoughts on changing SetLatch back to a single command and using my save/restore method.

    On another note, I believe I have the basics of the C cache driver. It now passes tests with flying colors, could use optimization. What I'm REALLY trying to get my head around is "extended commands." From my understanding, this is how we can pass cog commands. I think the mailbox structure will need to be modified, or perhaps not. I THINK we can use cache_interface.spin to pass commands, but I'm not sure about how we access this in C. Cache_interface.spin has some code like:
    PUB start(code, mbox, cache, config1, config2) | params[_INIT_SIZE]
        vm_mbox := mbox
        params[INIT_MBOX] := mbox
        params[INIT_CACHE] := cache
        params[INIT_CONFIG_1] := config1
        params[INIT_CONFIG_2] := config2
        long[vm_mbox] := $ffffffff
        cognew(code, @params)
        repeat while long[vm_mbox]
        vm_linemask := params[0]
        return vm_linemask
    pub readLong(madr)
        long[vm_mbox][0] := (madr&!CMD_MASK) | READ_CMD
        repeat while long[vm_mbox][0]
        madr &= vm_linemask
        return long[long[vm_mbox][1]+madr]
    pub writeLong(madr, val)
        long[vm_mbox][0] := (madr&!CMD_MASK) | WRITE_CMD
        repeat while long[vm_mbox][0]
        madr &= vm_linemask
        long[long[vm_mbox][1]+madr] := val
    I think we can substitute our transfers to do block writes, but as I said "vm_mbox" will probably need to be extended to 4 longs. What I'm REALLY pondering is what could actually be moved here, and where it lives in program memory. If things work like I HOPE they do, cache AND cache_interface live in-chip. Cache should always be loaded in cog *just like ramdriver* so if the interface lives in hub, we should be able to access SRAM at all times. This is even better if display writes can live in cache too, IMO. What I DO NOT understand is where SD code "lives." Of course I could be wrong and interface is just "part of code" and lives in external memory. If not there's still issues to be worked out, say Group3-4 is where things "break" IMO. If code's running along happily, then a cache hit, anything running needs to be "gracefully" shut down before cache read.

    I do understand your gut feeling about this not working. The more I work on it, the more it seems NEARLY impossible... Which is to say that I still think it's possible, but it's going to require serious work. Plus quite a bit of learning about the implementation. It will be interesting as things progress, although I'm not pushing this as top-priority right now. It would be nice to have C+,C++ running but with all the improvements in touch.spin I don't see the need for it yet.

    Top priority right now is getting expansion board running! I'm not looking forward to another RadioShack trip, but it will be worth it!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-05 23:09
    Hi averagejoe,

    With the new pasm draw routine I thought I would push the text as fast as it can go. So - take a font, move all the size data into a hub array, and leave the pixel data in external ram. We can print the letters with one pasm comand. And do characters one after the other quickly. So it is over 300 characters per second and can fill a screen with text in under a second. Maybe archive this one as it might be useful for a terminal program or text editor.

    Addit: I just thought of something. Ok, at the moment, the touch.spin object is sort of a garbage can full of routines and maybe you don't need them all. I think you are wanting to fork this code as well.

    Fundamental problem with spin as I can see it. You have object A, B and C. Object A is the main and B and C are sub objects. B can't talk to C. So say you split the touch.spin and move all the string routines over to another object. The string routines need to talk to the ram routines (this is also the reason the SD object resides within the touch.spin object and not in the main object).

    But... I see a solution. As we move more things into pasm, then objects are able to talk to each other. I think there are a bare minimum of pointers you might need to pass to any object at startup - the location of the three buffers we commonly use, the location of the cog parameters, and maybe some global values. I'm not sure this will work with the SD routines, but it ought to work with the routines that talk to external memory.

    What that means is we could split touch.spin up into a number of objects and you include the ones you want. And that might be a way of handling forks in the code in a neater way.

    It might also even be possible to do this for the SD object - you could set up some common hub locations with a flag to say "here is an SD command" and a little buffer for a file name, and then any object can open a file, read a block etc.

    The reason for all this is that looking at the text code on this post, the touch.spin contains some text drivers but what if you want to change them a little bit? They are not flexible enough.

    Also, maybe we can think about shrinking the sd driver code. At a fundamental level, open, close, write 512 bytes, read 512 bytes. So there must be some redundant code that can go to save space.

      _clkmode      = xtal1 + pll16x                        ' use crystal x 16
      _xinfreq      = 5_000_000
      ' demo using the fastdraw command - pasm draw, font size is in hub in an array.
      ' over 300 characters per second. 
      tch:           "Touch"                                 ' touchscreen driver
    VAR long Font[658] ' 0=size, 1=width,2=height, 3=xoffset, 4=yoffset, 5=amount to move next char, 6=ram location (126-32 characters)
    PUB Main | touchtest  ' debug value
      tch.SetWarmBoot                                           ' clears screen, sets a warm boot and reboots
    PUB TextFast | fontheight,f,fontaddress,ascii,jump,rambufferaddress,j,size,width,height,xoffset,yoffset,advance,pixeladdress,x,y
        tch.Clearscreen($FFFF)                              ' white background
        f := tch.Loadfont(string("Times20.ifn"))             'load font , file 2
        fontaddress := tch.getramlocation(f)
        fontheight := (tch.readramlong(fontaddress,$F8)>>24)       ' get the height
        repeat ascii from 32 to 126 ' read the font size data into hub (but leave the pixels in external ram)
          jump := tch.ReadRamLong(fontaddress,(ascii << 2) + 256)
          tch.RamToHub(fontaddress+jump>>1,20)  ' move data to rambuffer
          rambufferaddress := tch.fetchrambuffer   ' find out where rambuffer is
          repeat j from 0 to 5
            font[((ascii-32)*7)+j] := long[rambufferaddress][j]    ' could maybe do with a longmove but it isn't working
          font[((ascii-32)*7)+6] := fontaddress+((jump+32)>>1)
        tch.drawfastsetup ' set up for fast draw  
        repeat 300
          ascii := 65       ' letter to print
          f := ((ascii-32)*7) ' address
          size := font[f+0]
          width := font[f+1] 
          height := font[f+2]
          xoffset := font[f+3] 
          yoffset := font[f+4]
          advance := font[f+5]
          pixeladdress := font[f+6]
          tch.Drawfast(x+xoffset,y+yoffset,x+width-1+xoffset,y+height-1+yoffset)      ' draw on screen
          tch.RamToDisplay(pixeladdress,size)       ' move bytes from ram out to the display
          x += advance                ' new line if needed
          if x >220
            x := 0
            y += fontheight
  • average joeaverage joe Posts: 795
    edited 2012-09-09 21:39
    All very good thoughts! I've taken a small break from code to work on hardware. Built the basics of the expansion + midi + 4 audio outs. Then stopped to work on something I've had on the table for a while: Soft-Power...

    Here's the thought, take the /on|OFF terminals from the regulators and connect together. 20k pull-up to Vin connected to /on|OFF and collector of NPN transistor, emitter to ground. Capacitor on /on|off line for R/C constant discussed below.
    Now since all pins are used, I'd been thinking of ways to sense power-off condition and request power on. IF the transistor above is connected to I2C CLOCK will always be high, save during I2C transfers where it goes low for 1/2 period of clock. This is where the R/C comes in. Make C large enough to compensate for low period of clock. Need to run the figures for exact value.

    So now the propeller is able to "soft-power-off" by driving I2C CLOCK low for some time. I'm thinking a second or 2. This turns transistor off long enough to charge capacitor to above 1.6v per datasheet specs. Then regulator turns off, and so does everything else.

    Now the problem of turning things BACK ON! Well this is where things started to get complicated. Since I didn't want to add another mechanical button, I decided to reuse the reset button already on board. Connect /reset pin, through diode, to /on|OFF and when reset is pressed will ground /on|OFF pin. This powers up the regulators, and 10k pull-up on I2C clock pin will turn transistor back on. With transistor on, /on|OFF pin will be below 1.6v.

    That's the theory of operation. I have disconnected the /on|OFF pins for regulators and connected together. This works as expected, connected to gnd REGS are on. Connected to Vin, regs off. Tried 20k pull-up to Vin and mechanical switch to gnd and functions properly. Now time to build the rest! Should work like a charm!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-09 21:55
    Sounds very interesting.

    I've been deep inside the pacman coding. One nice thing is that with the new pasm draw routine, it is amazingly fast. I've got screen updates of all the ghosts and other things every 30ms but I think it can go faster than 10ms.

    In a general sense, I think in the past one of the limiting things with tile driver games has been getting the data out to the screen. For small games sprites can be stored in hub ram, but as the game reaches a certain level of complexity the sprites have to live in external memory (SD,eeprom, ram) and that limits the refresh speed. So game development sort of comes to a halt.

    With this design, the core of the design is fast ram to display transfer, with the propeller added later, and it makes for faster code. The original pacman is in Z80 assembly but for our purposes, Spin (with assembly calls) seems more than fast enough.

    In general terms, this board can do a lot more fun things that are yet to be coded.

    I have to confess I haven't soldered up an expansion board yet so any bugs you find are my fault!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-13 07:29
    I have the ghosts and pacman bouncing around randomly at the moment. Useful for testing if walls work.

    There are more things to code - collisions between pacman and ghosts, and the tunnel, and I need to redraw the food after the ghosts have moved over a food pellet.

    There is some ghost AI to add as well, and then icing sugar like adding fruit when you get a certain score.

    I'm hoping to play .wav files as is, or alternatively, use one of the synth programs. Lots of cogs still free.

    On a real pacman there are more things flashing, eg the score, and the power pills.
      _clkmode      = xtal1 + pll16x                        ' use crystal x 16
      _xinfreq      = 5_000_000
      tch:           "Touch"                                 ' touchscreen driver
       byte AltClock ' 0 = pacman mouth open, ghosts shimmer left, 1= pacman mouth closed, ghosts shimmer right
       long pac[20] ' 4 direction values (0123=RDLU), 5 X values (x8), 5 Y values, for (in order) pacman, red, orange, pink, blue, 5 speed values
       long Random ' every time use this add one (not really random but good enough for debugging)
       long milliseconds
       long GateCounter
    PUB Main | touchtest  ' debug value
      tch.SetWarmBoot                                           ' clears screen, sets a warm boot and reboots
    PUB Pacman | address,timer,tick,r
        tch.Clearscreen(%00000000_00000000)                 ' so something happens immediately
        tch.SDBMPtoRam(string("pactiles.bmp"))                ' file 2. File is a .bmp image but each 6x6 tile is continous for fast output
        tch.SDBMPtoRam(string("pacbut.bmp"))                  ' file 3 - control buttons
        tch.DrawBMPRam(3,70,215)                               ' draw the picture
        Gatecounter := 0                                    ' gate closed
        Setup                       ' start locations, speeds and directions
        tick := 50 ' ms between frames
          Move                                              ' move to new location
          case Milliseconds
            2000: ReleaseGhost(2)
            4000: ReleaseGhost(3)
            6000: ReleaseGhost(4)
          if Milliseconds >10000
            Milliseconds := 10000 ' don't increment any more
          timer += tick                                     ' increment timer
          milliseconds += tick
          if timer > 200
            altclock ^= 1   ' alternate 0,1,0,1  for pacman opening mouth, ghosts feet moving
            timer := 0                                      ' reset timer
          if gatecounter > 0
             gatecounter += tick  
          if gatecounter > 200
            gatecounter := 0
    PUB Setup
      ' pacman
        pac[0] := 0                ' looking left RDLU
        pac[5] := ((20*6)-3)<<8         ' x position (col*6)-3
        pac[10]:= ((17*6)-3)<<8         ' y position (row*6)-3
        pac[15]:= 600              ' speed, 256 is one pixel per clock tick
      ' red ghost
        pac[1] := 1                 ' red ghost eye direction
        pac[6] := ((20*6)-3)<<8             ' start x
        pac[11]:= ((11*6)-3)<<8             ' start y
        pac[16]:= 500                ' speed
        ' orange ghost
        pac[2] := 3                 ' orange ghost eye direction
        pac[7] := 100<<8             ' start x
        pac[12]:= 83<<8             ' start y
        pac[17]:= 500                 ' speed
        ' pink ghost
        pac[3] := 1                 ' pink ghost eye direction
        pac[8] := 116<<8             ' start x
        pac[13]:= 83<<8             ' start y
        pac[18]:= 500                 ' speed
       ' blue ghost
        pac[4] := 3                ' blue ghost eye direction
        pac[9] := 132<<8             ' start x
        pac[14]:= 83<<8             ' start y
        pac[19]:= 500                 ' speed
    PUB Move | direction,i,x,y,s
        ' work through characters in order
        ' use the current x,y and the direction of each character
        ' test ahead n pixels and see what is there eg a corridor, food pellet, or wall
        ' if hits a barrier, work out the available directions, apply rules (eg keypress, searching for pacman)
        ' and then change the direction
        ' redraw the background, redraw the character in the new position
        ' add speed to the current direction
        ' erase first If moving down or right then leaves one line of pixels. Erase these (or more if moving fast)
        ' (can't do a full black erase prior to redrawing as flickers a lot)
        ' the cage is not working as the lines are different. K instead of M along the top
        ' add or subtract speed
        repeat i from 0 to 4
          x:= pac[i+5]>>8            ' values used for clearrectangle below
          y:= pac[i+10]>>8
          s:= pac[i+15]>>8             ' speed, use this to calculate how many pixels to erase
          case pac[i]                ' direction
            0:ifnot walldetectR(i)
                pac[i+5]  += pac[i+15] ' increment x by speed
            1:ifnot walldetectD(i)
                pac[i+10] += pac[i+15] ' increment y by speed
            2:ifnot walldetectL(i)
                pac[i+5]  -= pac[i+15] ' decrement x by speed
            3:ifnot walldetectU(i)
                pac[i+10] -= pac[i+15] ' decrement y by speed
        DrawPacman(pac[0],pac[5]>>8,pac[10]>>8) ' bit shift 8 for higher x and y resolution
    PUB ReleaseGhost(i)
        GateCounter := 1          ' gate is open, close it later
        DrawBlank4(i)               ' delete the ghost in the cage
        pac[i] := 0                 ' ghost eye direction
        pac[i+5] := ((20*6)-3)<<8
        pac[i+10]:= ((11*6)-3)<<8    ' y position (row*6)-3
    PUB GateOpen
        DrawTile(32*6+12,19*6,12*6)    ' open gate
    PUB GateClose      
        DrawTile(32*6+14,19*6,12*6)    ' close gate
    PUB WallDetectL(i) 
       result := false
       if collision(pac[i],pac[i+5] - pac[i+15] ,pac[i+10] ) == 2
         pac[i] := NewDirection(i,2) ' hit wall to left so choose new direction   
         FixX(i)  '
         result := true
    PUB WallDetectR(i)
       result := false
       if collision(pac[i],pac[i+5] + pac[i+15],pac[i+10]) == 0
         pac[i] := NewDirection(i,0) ' hit wall to the right so choose new direction   
         DrawBlank4(i)       ' erase the old one prior to the fix move
         result := true
    PUB WallDetectD(i)
       result := false
       if collision(pac[i],pac[i+5],pac[i+10]+pac[i+15]) == 1
         pac[i] := NewDirection(i,1)' hit wall down so choose new direction
         result := true      
    PUB WallDetectU(i)
       result := false
       if collision(pac[i],pac[i+5],pac[i+10]-pac[i+15]) == 3
         pac[i] := NewDirection(i,3) ' hit a wall going up so choose new direction 
         result := true
    PUB DrawBlank4(i)
    PUB Collision(dir,x,y)  ' pass x and y, returns 0,1,2,3 for RDLU collision, 255 for no collision
      ' works on the centre tile where 0,0 is the top left, 6,6 is the centre with a 6x6 square around this
      ' so can encroach 3 on a wall tile and not hit it
      x := x>>8 ' convert to pixels
      y := y>>8 ' convert to pixels
      x +=6 ' centre in pixels
      y +=6 ' centre in pixels
      result := 255
      if dir == 0 and CheckWall(XYtoTile(x+3,y)) == true
         result := 0 ' right side hits a wall
      if dir == 2 and CheckWall(XYtoTile(x-3,y)) == true
        result := 2' left side hits a wall
      if dir == 3 and CheckWall(XYtoTile(x,y-3)) == true
        result := 3 ' top side hits a wall
      if dir == 1 and CheckWall(XYtoTile(x,y+3)) == true   
        result := 1 ' bottom side hits a wall
      ' special exemptions for the ghosts in the cage as need to use diff double lines so tracks above and below work
      if x>84 and x<156 and y>80 and y<94
        if y<84
          result :=3
        if y>89
          result :=1  
    PUB FixX(i) | x     ' x values must be 3,9,15 etc so 0-5 is 3, 6-11 is 9
       x := pac[i+5]>>8 ' x value in pixels
       x := x/6           ' divide by 6
       x := x*6           ' multiply by 6 so multiple of 6          
       x +=3              ' offset of 3
       pac[i+5] := x << 8 ' put new value back in
    PUB FixY(i) | y ' same as fixx
       y := pac[i+10] >> 8
       y := y/6
       y := y*6
       y +=3
       pac[i+10] := y << 8
    PUB XYtoTile(pixelx,pixely)
        result := (pixelx/6)+(40*(pixely/6))  'could do this faster with bitshifts instead of mul/divide
    PUB NewDirection(i,wall) | x,y,dir0,dir1,dir2,dir3' pass i = character, wall is RDLU 0123 the wall that has been hit
        x := pac[i+5]
        y := pac[i+10]
        x := x>>8 ' convert to pixels
        y := y>>8 ' convert to pixels
        x +=6 ' centre in pixels
        y +=6 ' centre in pixels
        case wall
          0,2:' hit a wall to the right or left so eliminate right and left as options as can't go back the same way
            dir0:= true    ' true is a wall or going back the same way
            dir2:= true
          1,3: ' hit a wall going down or up so eliminate up and down
            dir1:= true
            dir3:= true
        if CheckWall(XYtoTile(x+3,y)) == true  ' hits a wall to the right so eliminate this
            dir0 := true
        if CheckWall(XYtoTile(x-3,y)) == true ' if hits a wall to the left eliminate this  
            dir2 := true      
        if CheckWall(XYtoTile(x,y-3)) == true     ' if hits a wall up eliminate this
            dir3 := true
        if CheckWall(XYtoTile(x,y+3)) == true  ' if hits a wall down eliminate this
            dir1 := true
        if dir0 <> true     ' can go right
          if dir2<> true     ' if also can go left
            if ?random & 1 == 1 
              result := 0     ' go right
              result := 2     ' go left
            result := 0       ' go right
        if dir1 <> true       ' can go down
          if dir3<> true     'if can also go up
            if ?random & 1 == 1
              result := 1      ' go down
              result := 3      ' go up
              result := 1      ' go down
        if dir2 <> true      ' can go left
          if dir0 <> true      'if also can go right
            if ?random & 1 == 1 
              result := 0      ' right
              result := 2       ' left
          else                  ' only one choice left    
              result := 2
        if dir3 <> true         ' check up
          if dir1 <> true       ' if can go down as well
            if ?random & 1 == 1
              result := 1         ' go down
              result := 3         ' go up
              result := 3
         ' special exemptions for the ghosts in the cage as need to use diff double lines so tracks above and below work
        if x>84 and x<156 and y>80 and y<94 ' direction has already been changed by now so restore it
           result := pac[i]
    PUB CheckWall(n)                ' returns true if a wall at location m in maze, false if not
      result := false
       case byte[@maze][n]  
        "D","C","Z","V","X","\","P","W","Y","[","M","E","F","B","A","K","G","H","I","J","`","_","b","?","a","]","^": result := true                                  
    PUB DrawTile(n,x,y) ' draw tile n in location x,y
        tch.ramtodisplay(tch.getramlocation(2)+$36+((n<<5)+(n<<2)),36) ' $36 is the bitmap header offset, 36 (x32+x4) is number of pixels to draw
    PUB PacText(stringptr,x,y) ' the tiles also include text but only capitals. Happens to be stored at position 65 up (though numbers are not in the ascii position)
      repeat strsize(stringptr)
        x += 6
    PUB DrawMaze | x,y,address,c,n
       repeat y from 0 to 180 step 6
         n := (40*y)/6
         repeat x from 0 to 234 step 6
           'c := byte[@maze][40*y+x]
           c := byte[@maze][n]               ' faster as add is faster than multiply
           case c
             32..120:address := 143 + c                     ' walls of the maze 
             126: address := 16                             ' ~ is small food
             125: address := 20                             ' } is large food
    PUB Draw4(n,x,y) ' draw 4 tiles - many pictures are 4 tiles rather than 1. N is top left tile number
    PUB PacmanDie(x,y) | i
       repeat i from 0 to 11
    PUB DrawFruit | i             ' draw row of fruit
       repeat i from 0 to 7
    PUB DrawPacman(d,x,y) | a  ' d = direction 0,1,2,3,4= R,D,L,U,stationary
       case d                                               ' direction
         0: a:= 472
         1: a:= 474
         2: a:= 704
         3: a:= 706
       draw4(a+(altclock<<2),x,y)                           ' draw pacman
    PUB DrawPink(d,x,y)
       draw4(576+(d<<2)+(altclock<<1),x,y)             ' draw pink ghost with eyes correct direction and feet moving
    PUB DrawRed(d,x,y)
       draw4(448+(d<<2)+(altclock<<1),x,y)             ' draw red ghost
    PUB DrawOrange(d,x,y)
       draw4(640+(d<<2)+(altclock<<1),x,y)             ' draw orange ghost
    PUB DrawBlue(d,x,y)
       draw4(592+(d<<2)+(altclock<<1),x,y)             ' draw blue ghost
           byte "D~~~~~~~~~~~~~~~~~~ZY~~~~~~~~~~~~~~~~~~C"
           byte "D}ZwwwwwY~ZwwwwwwY~ZY~ZwwwwwwY~ZwwwwwY}C"
           byte "D~\VVVVV[~\VVVVVV[~\[~\VVVVVV[~\VVVVV[~C"
           byte "D~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C"
           byte "D~\VVVVV[~ZY~\VVVVVWXVVVVV[~ZY~\VVVVV[~C"
           byte "D~~~~~~~~~ZY~~~~~~~ZY~~~~~~~ZY~~~~~~~~~C"
           byte "nwwwwwwwY~ZcVVVVV[~\[~\VVVVVdY~Zwwwwwwwm"
           byte "nwwwwwwwY~ZY~~~~~~~~~~~~~~~~ZY~Zwwwwwwwm"
           byte "VVVVVVVV[~\[~^MMMMb??aMMMM]~\[~\VVVVVVVV"
           byte "~~~~~~~~~~~~~CwwwwwwwwwwwwD~~~~~~~~~~~~~"
           byte "PPPPPPPPW~XW~CwwwwwwwwwwwwD~XW~XPPPPPPPP"
           byte "DwwwwwwwY~ZY~CwwwwwwwwwwwwD~ZY~ZwwwwwwwC"
           byte "DwwwwwwwY~ZY~`KKKKKKKKKKKK_~ZY~ZwwwwwwwC"
           byte "DwwwwwwwY~ZY~~~~~~~~~~~~~~~~ZY~ZwwwwwwwC"
           byte "DwwwwwwwY~ZY~XPPPPPPPPPPPPW~ZY~ZwwwwwwwC"
           byte "JVVVVVVV[~\[~\VVVVVWXVVVVV[~\[~\VVVVVVVI"
           byte "D~~~~~~~~~~~~~~~~~~ZY~~~~~~~~~~~~~~~~~~C"
           byte "D~\VVWY~\VVVVVVVV[~\[~\VVVVVVVV[~ZXVV[~C"
           byte "D}~~~ZY~~~~~~~~~~~~~~~~~~~~~~~~~~ZY~~~}C"
           byte "JVV[~\[~ZY~\VVVVVVVWXVVVVVVV[~ZY~\[~\VVI"
           byte "D~~~~~~~ZY~~~~~~~~~ZY~~~~~~~~~ZY~~~~~~~C"
           byte "D~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C"
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-15 21:24
    I have started rewriting pacman using 8x8 tiles.

    Also I think it is easier to work with tiles if they don't require any external preprocessing. So, create a bitmap with all the tiles on it, then run it through a little spin routine at startup to strip off the bitmap header and then convert to a linear stream of pixels per tile. Just pass the tilesize and the number of columns and rows. I have tried this with an 8x8 tile for the background, a 8x8 font and 16x16 tiles for the actors.

    Loading in tiles uses these three lines of code
        tch.SDBMPtoRam(string("pacfont.bmp"))               ' file 4 font bitmap (8x8 font)
        tch.arraydim((16*16*64)/2)                          ' file 5 is the font tiles
        CreateTiles(5,4,8,16,16)                            ' create 8x8 font tiles

    So it is possible to use the bitmap files attached here. I think this will have a number of applications. Fonts are one, because you can "see" the font and edit it in paintshop or whatever, rather than running it through a preprocessor.

    I'm studying the ghost personalities here

    Grateful acknowledgement for the bitmaps here
      _clkmode      = xtal1 + pll16x                        ' use crystal x 16
      _xinfreq      = 5_000_000
      tch:           "Touch"                                 ' touchscreen driver
       long Blinky[6] ' red ghost direction UDLR, speed,x, y, offset (in current direction) mode (hunting, frightened, eyes, in cage)  
       long Pinky[6]
       long Inky[6]
       long Clyde[6]
       long Pacman[6]
    PUB Main | touchtest  ' debug value
      tch.SetWarmBoot                                           ' clears screen, sets a warm boot and reboots
    PUB MainPacman | address,timer,tick,r
        tch.Clearscreen(%00000000_00000000)                 ' so something happens immediately
        tch.drawfastsetup                                   ' setup fast drawing
        tch.SDBMPtoRam(string("pac8back.bmp"))              ' file 2. File is a .bmp image 
        tch.arraydim((8*7*64)/2)                            ' file 3 8x8 tiles, 8 wide, 7 high, this is in words so divide by 2 - file 3
        CreateTiles(3,2,8,8,7)                              ' pixels all one after the other in an array   
        tch.SDBMPtoRam(string("pacfont.bmp"))               ' file 4 font bitmap (8x8 font)
        tch.arraydim((16*16*64)/2)                          ' file 5 is the font tiles
        CreateTiles(5,4,8,16,16)                            ' create 8x8 font tiles
        tch.SDBMPtoRam(string("pac16.bmp"))                 ' file 6 all the ghosts and pacman (16x16 tiles)
        tch.arraydim((8*8*256)/2)                           ' file 7 pixels all in a row
        CreateTiles(7,6,16,8,8)                             ' pixels all one after the other in an array 
        tch.drawfastsetup                                   ' must do again if do any data transfers
        DrawMaze(3)                                         ' draw maze using file 3
        Pactext(string("PACMAN"),5,0*8,0*8)                 ' draw text using file 5
        Pactext(string("HI SCORE"),5,10*8,0*8)
        DrawTile16(7,9,2*8,34*8)                            ' draw number of lives left
        DrawTile16(7,9,4*8,34*8)                            ' draw number of lives left
        DrawTile16(7,48,24*8,34*8)                          ' draw fruit
        Setup                                               ' setup the ghosts
    PUB CreateTiles(destination,source,tilesize,ntileswide,ntileshigh) | s,d,soffset,doffset,tilex,tiley,npixels,tilesizetimesntileswide ' pixels linear so faster drawing
    ' take a bitmap made up of tiles and reorder so all the tile data is contiguous. Quicker to find tiles and to display them
        s := tch.getramlocation(source)+ $36 ' location in external ram and add $36 for bitmap header
        d := tch.getramlocation(destination) ' destination
        npixels := tilesize*tilesize
        tilesizetimesntileswide := tilesize*ntileswide     ' faster if precalculate this 
        repeat tiley from 0 to ntileshigh-1
          repeat tilex from 0 to ntileswide-1
            soffset := (tilex*tilesize) + (tiley*ntileswide) * npixels
            doffset := ((tiley*ntileswide)+tilex) * npixels
            repeat tilesize
              soffset += tilesizetimesntileswide
              doffset += tilesize
    PUB DrawTile8(f,tilenumber,x,y) ' file, tilenumber, x, y. Optimised for 8x8 tiles - can do bitshifts instead of divides/multiplies
        tilenumber := tilenumber << 6 ' multiply by 64 to get the start address
        tch.ramtodisplay(tch.getramlocation(f)+tilenumber,64) ' display
    PUB DrawTile16(f,tilenumber,x,y) ' file, tilenumber, x,y. Optimised for 16x16 tiles (bitshifts faster than multiply)
        tilenumber := tilenumber << 8 ' multiply by 256 to get the startaddress
        tch.ramtodisplay(tch.getramlocation(f)+tilenumber,256) ' display       
    PUB DrawMaze(f) | x,y,c,n   ' 28 wide, 36 high
       repeat y from 0 to (288-8) step 8
         n := (28*y)>>3                     ' width times y and divide by 8
         repeat x from 0 to (224-8) step 8
           c := byte[@maze][n]               ' faster as add is faster than multiply
    PUB PacText(stringptr,f,x,y) 'string, ram file (array) to print from, x,y
        repeat strsize(stringptr)
          x += 8
    PUB Setup
      Blinky[0] := 2 ' travelling left
      Blinky[1] := 0 ' speed
      Blinky[2] := 14*8+4 ' tilex 14,13 is startup for Blinky
      Blinky[3] := 13*8+4 ' tiley
      Blinky[4] := 0 ' offset (add speed to this each clock tick and use to recalculate the tile. Increment tile if in the next one)
      Blinky[5] := 0 ' mode = hunting
      Pinky[0] := 1 
      Pinky[1] := 0 
      Pinky[2] := 11*8+8 
      Pinky[3] := 16*8+4 
      Pinky[4] := 0 
      Pinky[5] := 1 ' in cage
      Inky[0] := 0
      Inky[1] := 0 
      Inky[2] := 13*8+8 
      Inky[3] := 16*8+4 
      Inky[4] := 0 
      Inky[5] := 1
      Clyde[0] := 1
      Clyde[1] := 0 
      Clyde[2] := 15*8+8
      Clyde[3] := 16*8+4 
      Clyde[4] := 0 
      Clyde[5] := 1
      Pacman[0] := 1
      Pacman[1] := 0 
      Pacman[2] := 14*8
      Pacman[3] := 25*8+4 
      Pacman[4] := 0 
      Pacman[5] := 2 ' startup
    PUB DrawBlinky
       ' need to add in offset
    PUB DrawPinky
    PUB DrawInky
    PUB DrawClyde
    PUB DrawPacman
    DAT maze ' tile number
    '         0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27    
        byte 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 ' 0    
        byte 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 ' 1
        byte 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 ' 2 
        byte 25,21,21,21,21,21,21,21,21,21,21,21,21,30,29,21,21,21,21,21,21,21,21,21,21,21,21,26 ' 3 
        byte 23,18,18,18,18,18,18,18,18,18,18,18,18,48,47,18,18,18,18,18,18,18,18,18,18,18,18,24 ' 4 
        byte 23,18,41,46,46,42,18,41,46,46,46,42,18,48,47,18,41,46,46,46,42,18,41,46,46,42,18,24 ' 5
        byte 23,19,48,16,16,47,18,48,16,16,16,47,18,48,47,18,48,16,16,16,47,18,48,16,16,47,19,24 ' 6
        byte 23,18,43,45,45,44,18,43,45,45,45,44,18,43,44,18,43,45,45,45,44,18,43,45,45,44,18,24 ' 7
        byte 23,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,24 ' 8    
        byte 23,18,41,46,46,42,18,41,42,18,41,46,46,46,46,46,46,42,18,41,42,18,41,46,46,42,18,24 ' 9
        byte 23,18,43,45,45,44,18,48,47,18,43,45,45,38,37,45,45,44,18,48,47,18,43,45,45,44,18,24 ' 10    
        byte 23,18,18,18,18,18,18,48,47,18,18,18,18,48,47,18,18,18,18,48,47,18,18,18,18,18,18,24 ' 11 
        byte 27,22,22,22,22,42,18,48,39,46,46,42,16,48,47,16,41,46,46,40,47,18,41,22,22,22,22,28 ' 12   
        byte 16,16,16,16,16,23,18,48,37,45,45,44,16,43,44,16,43,45,45,38,47,18,24,16,16,16,16,16 ' 13 
        byte 16,16,16,16,16,23,18,48,47,16,16,16,16,16,16,16,16,16,16,48,47,18,24,16,16,16,16,16 ' 14    
        byte 16,16,16,16,16,23,18,48,47,16,50,22,54,20,20,55,22,51,16,48,47,18,24,16,16,16,16,16 ' 15 
        byte 21,21,21,21,21,44,18,43,44,16,24,16,16,16,16,16,16,23,16,43,44,18,43,21,21,21,21,21 ' 16   
        byte 16,16,16,16,16,16,18,16,16,16,24,16,16,16,16,16,16,23,16,16,16,18,16,16,16,16,16,16 ' 17 
        byte 22,22,22,22,22,42,18,41,42,16,24,16,16,16,16,16,16,23,16,41,42,18,41,22,22,22,22,22 ' 18    
        byte 16,16,16,16,16,23,18,48,47,16,52,21,21,21,21,21,21,53,16,48,47,18,24,16,16,16,16,16 ' 19 
        byte 16,16,16,16,16,23,18,48,47,16,16,16,16,16,16,16,16,16,16,48,47,18,24,16,16,16,16,16 ' 20   
        byte 16,16,16,16,16,23,18,48,47,16,41,46,46,46,46,46,46,42,16,48,47,18,24,16,16,16,16,16 ' 21 
        byte 25,21,21,21,21,44,18,43,44,16,43,45,45,38,37,45,45,44,16,43,44,18,43,21,21,21,21,26 ' 22
        byte 23,18,18,18,18,18,18,18,18,18,18,18,18,48,47,18,18,18,18,18,18,18,18,18,18,18,18,24 ' 23   
        byte 23,18,41,46,46,42,18,41,46,46,46,42,18,48,47,18,41,46,46,46,42,18,41,46,46,42,18,24 ' 24
        byte 23,18,43,45,38,47,18,43,45,45,45,44,18,43,44,18,43,45,45,45,44,18,48,37,45,44,18,24 ' 25   
        byte 23,19,18,18,48,47,18,18,18,18,18,18,18,16,16,18,18,18,18,18,18,18,48,47,18,18,19,24 ' 26
        byte 34,46,42,18,48,47,18,41,42,18,41,46,46,46,46,46,46,42,18,41,42,18,48,47,18,41,46,36 ' 27  
        byte 33,45,44,18,43,44,18,48,47,18,43,45,45,38,37,45,45,44,18,48,47,18,43,44,18,43,45,35 ' 28
        byte 23,18,18,18,18,18,18,48,47,18,18,18,18,48,47,18,18,18,18,48,47,18,18,18,18,18,18,24 ' 29 
        byte 23,18,41,46,46,46,46,40,39,46,46,42,18,48,47,18,41,46,46,40,39,46,46,46,46,42,18,24 ' 30
        byte 23,18,43,45,45,45,45,45,45,45,45,44,18,43,44,18,43,45,45,45,45,45,45,45,45,44,18,24 ' 31   
        byte 23,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,24 ' 32    
        byte 27,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,28 ' 33
        byte 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 ' 34
        byte 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 ' 35          
    800 x 600 - 103K
    128 x 128 - 48K
    128 x 128 - 48K
    64 x 56 - 11K
  • Mark_TMark_T Posts: 1,981
    edited 2012-09-16 04:59
    Nice work indeed! Very impressed. Since this is such a long thread I was wondering what the hardware setup you are currently using? I happen to have just acquired a couple of 320x240 LCD modules from eBay and have a few miniature joystick switches needing a good home!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-16 05:58
    Hi Mark, the hardware is a 100x160mm board that average joe and I have designed. It has gone through a number of revisions but it is essentially a propeller chip, two ram chips and some counter chips, plus the display. average joe has some boards available for sale.

    Miniature joysticks sound interesting. I wonder if we could convert the analog signal into something an I2C A to D chip could read? That would make a great controller for this game.
  • average joeaverage joe Posts: 795
    edited 2012-09-16 07:23
    Hi Mark,

    I do have boards for sale, but they will not be compatible with the displays you mentioned in a previous post. :( Might be able to figure something out, then again maybe not...
    PM me if you're interested!

    BTW: current schematic and parts list here:

    James, I almost ordered 2 of these a couple days ago when I ordered another propPlug:

    I think they would be PERFECT for the `2302.

    Almost grabbed one of these too:

    Have other stuff to (re)-order right now...

    I soldered up another board, and took a video. I have some editing done on the build video but decided to scrap old footage because I was doing it wrong!!! This time I did sockets, REGULATORS *directly to board, DUH...* and continued.

    Been super-busy... And gotta run!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-09-16 17:35
    I just bought a little joystick on ebay.

    Also the MCP2302 will work really well with this. For something like pacman, you could use the screen or the joystick as the controller.

    Just going off on a tangent, I have been doing some research on the I2C bus as this can keep running in the background with a cog without having to be stopped for screen refreshes. The PCF8591 is a nice chip - one analog output, 4 analog inputs, three pins to select one of 8 so lots of I/O possible. Schematic is simple and available on ebay for $1.20 PDIP for easy soldering.
  • average joeaverage joe Posts: 795
    edited 2012-09-16 18:55
    OOOO! That's a promising looking chip!

    Need to get expansion board going, still have not had time :(
    I will be picking up a couple of analog sticks next time I order from parallax. Hopefully they'll have the FULL PING kit then.
  • average joeaverage joe Posts: 795
    edited 2012-10-18 01:35
    Hi James, I've been quite busy but found some free time on my hands. Now I've really been meaning to get the expansion board up and running. Had some ideas about how to accomplish this but still have not implemented anything. At this point I have been thinking about getting SidSynth running on the expansion and using the touchburger to change parameters. I would also like to use the expansion's programming port to communicate with the pc using the midi in and outs. But there are some significant hurtles that need to be overcome...

    First, sidsynth has about 300 longs left after removing debugging code. With the debug code, there's 80 longs left which I imagine is filled with stack *there is a bug mentioned with debug code running, my guess would be not enough stack* If I decided to use SPDIF I could free a cog and about 8k... Still thinking about this.

    Second, and most important, I can't figure out how to implement the protocol. My first thought was down and dirty. Use 2 pins for bidirectional asynchronous serial. Have the expansion watch for group change. But on second thought I see some real issues with this. For example, serial transfer is taking place when screen update is called *this could be prevented in code but adds significant complexity*

    My next thought was to use a parallel transfer, using the memory cog. My thought is transfers would need to be at least 2 bytes. First byte from host to slave giving read/write command, second byte containing data. *minimum* Seems like a good start but still has some downfalls, IE lack of addressing.

    So what I'm asking is this...Do you have any insight as to the most flexible way to implement this? Any thoughts would be greatly appreciated!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-10-18 18:32
    You might be able to do serial transfer while doing a screen refresh if you use the programming pins for the serial, and use a serial object that fits entirely in a cog. Buffer things into hub and if the buffer is big enough, worry about what is in the buffer after a screen update?
  • average joeaverage joe Posts: 795
    edited 2012-10-18 19:50
    You know, I thought about using the programming pins... Seems like cheating though :D

    The 8-bit parallel bus keeps making me drool since it should be able to transfer quite quickly and be very lightweight. My thought was to modify 4port full duplex serial and change port4 to transfer using the parallel bus. Maybe this is not the way to go after all.

    The problem is that there are SO MANY ways to do it, it's hard to pick just one. Might be best to stick with using a serial port at this point since SidSynth has 4port running 2 ports already.

    The goal at this point is to get a GUI control for the parameters of the synth, maybe even use that cool keyboard you made to play notes :) I would also like to use sidsynth with the midi ports on the expander. Then I start thinking about how cool it would be to have "midi - routing" functions running on the expander. IE have midi-in port "echo" to programing port for serial midi to computer. Then serial-midi out "play" sidsynth. This could be turned on or off at will.

    With the GUI running, I'd like to control parameters and possibly save patches to SD card for later use. The touchburger code should be a snap, provided I can figure out the SidSynth code. It's a masterpiece and I don't want to mess it up!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-10-18 20:12
    Maybe use the serial ports for the moment - should be easy to drop in existing objects.

    Re an 8 bit bus, I'm working on a group of boards that use an "8080" style of bus - 20 pins = 8 data, 8 address (256 ports), read, write and power. I've got 4 boards so far. I'm starting with the generic idea that each board is programmed once and then acts as a functional unit, and only the master is reprogrammed. Take the SD card for instance - as soon as you add an SD card to a propeller chip, you lose 1/3 of the hub memory for code. Add in a TV or VGA display and you lose half, and there is never enough code space for a decent program. So if a separate board has an SD card and a VGA socket and a keyboard etc, then all that code can be offloaded. But you need the speed for transferring data and I think devoting something like 11 propeller pins to driving the bus gives a good compromise between speed and pin count.

    The data bus is bidirectional and the address bus might be too so I am thinking of a system like on the I2C bus with one 10k pullup and then devices can pull the line down. ie rather than High and Low signals, the signals are HiZ and L, with a weak pullup. So then any device can talk to any other device. Specs here are a work in progress!

    I'm going off on a tangent here though.

    For your problem, the serial port sounds like an answer.
  • average joeaverage joe Posts: 795
    edited 2012-10-18 23:50
    Okay, I THINK I've got this. The plan us to use 4-port serial running in SidCog, with 4-port serial on touchburger. Need to figure out coding for CTS/RTS using groups.. I think I might need to OR RTS with group4? Might be a way to do this in code though.

    Sounds like you've got great ideas, love the 8080 style bus idea. Using 20 pins should be VERY fast! Can't wait to see what materializes!


    Well I wired up a `244 isolation circuit. I think this should work, just need to shutdown and start serial cog IN MASTER for display updates. I'll start coding tonight and let you know how it goes!


    I tried coding up a simple loop to start the serial driver, wait some time to fill it up.
       exp  :          "fullDuplexSerial4portJM"                             ' 4 port serial driver with 
    .. (init code)
     exp.init                                              ' init serial driver
     exp.AddPort(0,13,16,14,15,0,(expMode),expBaud)        ' set master
    ...(finish init code) 
    PUB GetExpSTRING | ptr , t                             '' returns a number of characters
     exp.start                                              ' start serial driver 
       ptr := 0                                             ' zero pointer
       pause1ms(100)                                        ' ?wait? for buffer to fill?                                                
       repeat while ((t:=exp.rxcheck(0)) <> -1)             ' empty serial buffer
         byte[@buffer2][ptr] := t                           ' into buffer2 
      exp.Stop                                              ' stop RS232 driver, need to do this gracefully??
      result := ptr                                         ' set result to pointer
    Not the best way to do this.. I'm not even sure this would work? There's a chance of losing data this way. What I'd LIKE to do is modify FullDuplex to use Open drain... then I could pull RTS low in spin, clear the buffer, then stop the cog. I think I've narrowed the code, but it's a tricky one...
  • average joeaverage joe Posts: 795
    edited 2012-10-21 17:06
    Well I've had some ideas on shutting the serial cog down on the master in a graceful way. The problem is: with the expansion connected, the touchburger fails to boot! Need to figure out why.

    This was after I realized the I2C bus was missing pullups... So the expander programs now. Must be close!

    Spent the night trying to figure out why my `244 circuit didn't work. Turns out the 2 power headers are labeled wrong. 5v is actually gnd and GND is 5v. Now to rebuild my 244 again...


    Okay, I'm at a loss... It seems like any load on GP3 pin causes the issue. Having trouble capturing it with the `scope.
    Right now I'm getting Random_Reboots during load desktop. Unplug the `244 from the group pin and it boots fine. Hook the scope up to the pin and RR..

    Here's a capture. The dip is where it reboots.

    And it just starts working, kind of... Not stable. I'm willing to bet it was the 100k resistor networks on Pins 0-16. I'll build another board and re-check. Otherwise it's the cable. I thought a 6" section of floppy cable would work but maybe not!
    320 x 240 - 9K
    320 x 240 - 7K
  • average joeaverage joe Posts: 795
    edited 2012-10-31 01:52
    I have not officially tested this yet, but I think I have the expansion figured out. It's actually fairly simple. Replace the resistor array with a socket, and 74hc244. "Modify" the 244 to get it's power from the headers *(which are labeled incorrectly ;) * and wire the group to enable. Works out kinda nice! I'll edit later for clarity.

    1024 x 768 - 116K
    1024 x 768 - 114K
  • average joeaverage joe Posts: 795
    edited 2012-11-04 01:40
    I have it working!!! There's still a bug somewhere...

    Needed to add a couple no-ops in the assembly driver since there was a problem with the 1'st byte of RamToHub becoming corrupted. That one took me a while to figure out.
                            call    #set161and373           ' set up the 161 counter and change to group 2
                            and     dira,maskP16P31         '%11111111_11111111_00000000_00000000 inputs
                            andn    outa,maskP16            ' memory /rd low
    ramtohub_loop           mov     data_16,ina             ' get the data
                            wrword  data_16,hubaddr         ' move data to hub
                            andn    outa,maskP20            ' clock 161 low
                            or      outa,maskP20            ' clock 161 high
                            add     hubaddr,#2              ' increment the hub address 
                            djnz    len,#ramtohub_loop
                            or      outa,maskP16            ' memory /rd high  
                            jmp     #init                   ' ' tristate pins and listen for commands

    Then, I needed to modify the group selection as follows
    PUB SelectMemGroup                                      ' select group 1 for memory transfer
       spi.stop                                             ' and stop any other cogs here too if needed
       DIRA |= %00000000_00011111_11111111_11111111         ' enable these pins for output
       OUTA |= %00000000_00011111_00000000_00000000         ' set /rd /wr /disp wr and 161 clock high
    PUB SelectSPIGroup
       DIRA &= %00000000_00000000_00000000_00000000         ' so no clashes with the cogs using P0-P2 set these as inputs and P3-P5, and expansion pins
       LatchGroup3                                          ' select group 2 for spi transfers
       TouchStart                                           ' start the touchscreen cog                                                        
       ' may need to set some pins here as inputs or outputs with a dira

    Now I've still had some issues using the first "port" OR expander pins 0-3
    expander pins
    0   - 1  -  2  -  3  -  4  -   5  -  6   -  7
    I   - O  -  I   - O  -  I   -  O  -  I   -  O
    O   -  I  - O  -  I   - O   -  I   -  O  -  I                     
    19  - 12  - 13 - 14  -  15  - 16   -  17 - 18
    touchburger pins
    ExpRX     = 16
    ExpTX     = 19
    ExpCTS    = 18
    ExpRTS    = 17
    ExpMODE   = exp#OCTX
    EXP_BRATE = 115200
       exp  :          "fullDuplexSerial4portJM"                             ' 4 port serial driver with 
    PUB exp_test  | ptr, font, p
     beginProgram                                           ' warmBoot
      font := Loadfont(string("Par16.ifn"))                 ' black on white 16 point, load and set font to file
      Clearscreen(BackFontColor)                            ' clear screen to BackFontColor = font file loaded above
      curx := 0                                             ' return Cursor to X 0
      cury := 0                                             ' return Cursor to Y 0
      repeat                                                ' loop
        exp.init                                            ' init serial driver
        exp.AddPort(0,ExpRX,ExpTX,ExpCTS,ExpRTS,EXP#DefaultThreshold,ExpMODE,EXP_BRATE)  ' create expansion port
        SelectSPIGroup                                      ' Change to group3 for transfers
        exp.start                                           ' start serial driver
        ptr := 0                                            ' zero pointer
        pause1ms(50)                                        ' ?wait? for buffer to fill?
        exp.Stop                                            ' stop expander port
        repeat while ((p:=exp.rxcheck(0)) <> -1)            ' empty serial buffer
          if 32 < p < 126                                   ' check for printable character
            byte[@sdbuffer][ptr++] := p                     ' and copy into sdbuffer
        IF ptr > 0                                          ' if captured character
          byte[@sdbuffer][ptr] := 0                         ' zero terminate string
          TextT(font,@sdbuffer)                             ' and print message on display
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-11-04 02:01
    Great work!

    What are you going to be using the expansion board for?
  • average joeaverage joe Posts: 795
    edited 2012-11-04 03:28
    I have several things in mind for the expansion. I figured I'd start with MIDI and Audio wired up. I'm planning on building a skin for SidSynth, similar to pc program included with a previous build. Right now it's simple debugging, ensuring reliable serial port.

    There's still a glitch somewhere, but it's one of those pesky ones that pops up and goes away at random. Well not entirely random. IF rebooting expansion board, sometimes display draws garbage.

    Still much work to do. I'll record a demo of the debugger in a few.

    Here's some photos of the debugger, uploading video in a few. This only works for the initialize debugging, once I start playing notes the screen bugs out.
    There's a hardware error on the expansion - RN2-Pin2 goes to Q19/OK-1-pin6. OOPS!
    Need to do a bunch more testing as things are still not "stable"
    1024 x 1365 - 231K
    1024 x 1365 - 218K
  • average joeaverage joe Posts: 795
    edited 2013-01-27 00:55
    Erm, well. Efforts directly connecting the wiznet812MJ to the touchburger soured so plugged the expansion board back in. Seems that pesky bug is gone? Not sure what I did, but I've been working through a clean-up of Touch.Spin and I can no-longer replicate my bug!!! A bug I found : Updating the cursor Y position was wrong for text, would cut off portion of last write.
    PUB lf                                                  ' line feed, move up one
        cury += FontHeight                                  ' next line
        if cury + FontHeight > screenheight                 ' if off the bottom of the screen then clear screen, start at the top
    '    if cury > screenheight                 ' if off the bottom of the screen then clear screen, start at the top           missed the last write -OLD
          ClearRectangle(0,0,screenwidth,screenheight,BackFontColor) ' clear the screen 
          cury := 0                                         
    Also: release ALL pins in SPI GROUP.
    PUB SelectSPIGroup
       DIRA &= %00000000_00000000_00000000_00000000         ' so no clashes with the cogs using P0-P2 set these as inputs and P3-P5, and expansion pins
       LatchGroup3                                          ' select group 2 for spi transfers
       TouchStart                                           ' start the touchscreen cog  
    Also: for stability with 2 displays and the expansion, seems we need a no-op before entering the main loop of Ram2Hub and Ram2Display
                            call    #set161and373           ' set up the 161 counter and change to group 2
                            and     dira,maskP16P31         '%11111111_11111111_00000000_00000000 inputs
                            andn    outa,maskP16            ' memory /rd low
    ramtohub_loop           mov     data_16,ina             ' get the data
                            wrword  data_16,hubaddr         ' move data to hub
                            andn    outa,maskP20            ' clock 161 low
                            or      outa,maskP20            ' clock 161 high
                            add     hubaddr,#2              ' increment the hub address 
                            djnz    len,#ramtohub_loop
                            or      outa,maskP16            ' memory /rd high  
                            jmp     #init                   ' ' tristate pins and listen for commands
    pasmramtodisplay        andn    outa,maskP19            ' CS low
                            and     dira,maskP16P31         ' %11111111_11111111_00000000_00000000 so prop pins 0-15 HiZ
                            andn    outa,maskP16            ' ram /rd low
    ramtodisplay_loop       andn    outa,maskP18            ' ILI write low
                            or      outa,maskP18            ' ILI write high
                            andn    outa,maskP20            ' clock 161 low
                            or      outa,maskP20            ' clock 161 high
                            djnz    len,#ramtodisplay_loop
                            or      outa,maskP16            ' mem /rd high
                            or      outa,maskP19            ' CS high 
                            jmp     #init

    I'm also attaching the schematic I drew up describing the communication channel I hacked to the expansion. Looks like it works, need to test reliability of communication. Oh yea here's the simple debugging program I've been working on.
    ' //////////////////////////////////////////////////////////////////////
    ' touchburger debugger program, simple serial to text on screen        /
    ' //////////////////////////////////////////////////////////////////////
    ' /                                                                    /
    ' //////////////////////////////////////////////////////////////////////
    ' /////          Clock settings                                    /////
         _clkmode   = xtal1 + pll16x       ' use crystal x 16              /
         _xinfreq   = 5_000_000            ' use 5MHZ crystal              /
    ' //////////////////////////////////////////////////////////////////////
    ' /                                                                    /
    '               expansion pin config, slave currently 1 way.
    ' /                                                                    /
    ' //////////////////////////////////////////////////////////////////////
      ExpRX     = 16
      ExpTX     = 19
      ExpCTS    = 14
      ExpRTS    = 15
      ExpMODE   = exp#OCTX
      EXP_BRATE = 115200
    ' //////////////////////////////////////////////////////////////////////
    VAR     byte          buffer[512]
    'dat  default_font byte   "Par16.ifn",0        ' default font
    dat  default_font byte   "4x6.ifn",0        ' default font
    OBJ     tch  : "Touch3"
            exp  : "fullDuplexSerial4portJM"             ' 4 port serial driver with 
    PUB Ini  | ptr, font, p
      tch.beginDesktop("S")                                                   ' warmBoot
      font := tch.Loadfont(@default_font)                               ' black on white 16 point, load and set font to file
      tch.Clearscreen(tch.GetBackFontColor)                                          ' clear screen to BackFontColor = font file loaded above
      tch.SetCursor(0,0)                                                      ' 
      repeat                                                                  ' loop
        exp.init                                                              ' init serial driver
        exp.AddPort(0,ExpRX,ExpTX,ExpCTS,ExpRTS,EXP#DefaultThreshold,ExpMODE,EXP_BRATE)  ' create expansion port
        tch.SelectSPIGroup                                  ' Change to group3 for transfers
        exp.start                                           ' start serial driver
        ptr := 0                                            ' zero pointer
        tch.pause1ms(50)                                        ' ?wait? for buffer to fill?
        exp.Stop                                            ' stop expander port
        repeat while ((p:=exp.rxcheck(0)) <> -1)            ' empty serial buffer
          if 31 < p < 126                                   ' check for printable character
            byte[@buffer][ptr++] := p                     ' and copy into sdbuffer
        IF ptr > 0                                          ' if captured character
          byte[@buffer][ptr] := 0                         ' zero terminate string
          tch.TextT(font,@buffer)                             ' and print message on display

    This runs on the touchburger and gives the expansion 1-TX channel. I have not implemented RX yet. There's room for 2 ports on the bus if we really want to push it. I was having problems with one-way recieve on the touchburger, but now it seems better. Still need to test everything thoroughly.

    I have 1 unpopulated expansion board left and will record the "fix" for the comms channel. The resistors would probably work, I was just worried about an Off-The-Rails program running on the expansion board causing problems with the touchburger. Also prevents the need from stopping and starting the cog on SLAVE, still need to stop and start cog on MASTER *just like SPI*

    oh yea, BTW... icons for PacMan and the Debugger
    59 x 60 - 11K
    59 x 60 - 11K
  • average joeaverage joe Posts: 795
    edited 2013-02-15 11:00
    A few more posts to this thread, then I'll start a new one *I know, I've been saying that for some time now*

    Picked up a 7", 800x480 display on ebay. Getting it to work has been a bit tricky though. Because it is significantly larger, it does not fit in Display 1 slot. Took me a while to figure out that's why I couldn't initialize it. So, connected SD pins to Display 2 slot as well. Just to realize there's an error in the schematic! Display 2 slot has P5 to 24-T_busy, not 26-T_out. Can't believe I missed that. Code's still a mess. One huge problem I've found but not had time to track down. When screenWidth and screenHeight are modified to proper resolution, icons won't draw properly in desktop.

    There's a few decisions to make at this point. Largely, how to handle the multiple displays. For the 2.4" and 3.2", using the ASCII character worked pretty well. But now with the 3 different display types, one with a different resolution, I propose using separate touch.spin files. This means compiling programs for each display. Maybe we can have the 2.4" and 3.2" share programs, need to think on this still. One tool I've thought about using is BST's conditional compiles. It would make it possible to keep things in one file, and just change a couple tags when compiling. Still not sure though.

    I propose changing DisplayMode to DisplayType and using "2" for 2.4, "3" for 3.2" and "7" for 7". Files on the SD card have max 7 character name, followed by display type. As I said, it would be possible to have the 2.4" and 3.2" share programs but they will display just a bit faster if they don't. Plus code size is smaller...

    I'm also thinking about another variation of the spin file. One file "touchP.spin" and "touchD.spin". TouchP is for programs that don't need to initialize the display *most* and TouchD is for those that do *Desktop*.

    I've also done a significant amount of tuning of touch.spin *for the SSD* mostly ASM work, some small modifications to Spin as well. Got the drawFast a little faster. Unrolled the loop and made sure there were no hub windows missed. Tried unrolling the BMP to 16bpp but failed. I'll look back into this after getting this new display working properly. It also dawned on me how to speed up loading of BMPs. Instead of reversing the order when transferring from SD to RAM, just change the entry mode for RAM to display RAM. I was also pondering just keeping width and height from the header instead of the whole 54 bytes. Still much work to do. Any thoughts greatly appreciated!

    Now if only Raymond would offer the Graphics shield with access to all 16 pins. Then I would need to buy one. I'm still thinking about it, but it seems like a waste of perfectly good ram...
    1024 x 768 - 85K
    1024 x 768 - 53K
  • Igor_RastIgor_Rast Posts: 357
    edited 2013-02-18 08:42
    Ok , so i though its about time I also jump into action.

    Fist of all @ average joe and Dr_Acula Masssively immpressive work . thanks for sharing it

    I always dreamed about building my own stuff, with this propeller more and more I see almost everything is possible with this propeller.
    I have been reading back and forth on this tread and think its time I also jump into some coding with an lcd some time soon

    a touchscreen GUI with my projects is almost like finally going to space for an astronaut . for me than :p
    have been working on with all different kinds of sensors en modules(temp + humidity + light + CO2 + Ph + EC ) last was the wiznet W5200 . with Mike G who also is the genious on this thing. puting together a webserver, with my controller . the touchscreen is what im missing :p

    , it isn't really clear to me how the lcd is connected to the propeller , which of all the schematics is the good one
    is it this one or are there modifications made to the board later on that are not changed in the schematic ?.
    if I understand correctly , I can also connect the lcd directly pin for pin to the propeller , but i wil be having slower speeds. I dont want that :smile:
    I would realy like to make it the best possible way, so adding the external couters, and memory like you were mentioning .

    the idear of having 2 propellers togeter working as one system has also daunted me , because with the wiznet i am almost running out of code space, adding a lcd would deffinintly make it even worse. A second prop , also for the pins , so more sensors can be connected or controled. would be verry nice , but cant realy find a good nice clear example to connect them. maybe putting the lcd, wiznet,sdcard. on one prop . the other one driving relays , indication leds, buttons ( o I dont need those anymore then) and all sensors I want to add ,.
    see some talk about the Prop B version. that would make allot of difference those extra pins , even better the prop 2 . but with the prop 2 i am affraid i have to go invent all my sensor routines again , just want to use the prop1 .

    are there any boards for sale left ? if so how much would it cost me ( shiping to the netherlands).
    I prefeur a good scematic because i can easly make a proto pcb at scool ,I do have to drill the vias manualy . but hey , beats 3 weeks waiting any day. to get somthing to work that is

    I also stil have to order a lcd
    had 4.3 inch in mind before . dont hear you mentioning it anywhere . maybe ill just go for the 3.2 inch . or both :p
    any suggestions ??
    so its going to be some time before ill be talking about that , but i realy look forward to it .

  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-02-18 14:44
    @averagejoe, I've been following the posts on facebook - from the lines to the icons and I think you have it nailed. Great stuff!

    Sorry about the bug on the board - my bad. *facepalm*

    I like the code changes. Re the board, given the size of the display, one could think about redoing the board layout so the board sits under the display. How much did the display cost? If it was less than the cost of two of the smaller displays, then maybe we move all the code over to the bigger display? That gets around your problem of having different code.

    If we ever do a surface mount smaller board, then that would fit underneath one of the smaller displays.

    I have a whole system of new boards that I am building and testing at the moment that plug together with 10 pin headers. Everything is via these headers so you can easily change from a VGA or TV or touchscreen setup. The I2C bus also comes out to a 10 way header and there are lots of peripheral I2C bus boards so that could go on the touchscreen board. Not quite ready to release photos yet as there are still some bugs (like the PCB fab house using a mirror image of one of the gerber files).

    Re Igor_Rast, yes that schematic is the correct one. Files are Eagle 5.0 - I am not sure if they will open in the new version of Eagle 6. Probably will. Re connecting directly to the prop - yes you can but it is too slow to be practical. Things like dumping fonts out to the display for fast scrolling through text really do work a lot better if the font is stored in external ram.

    averagejoe - do you have a link to the supplier of the display?

    Addit: E'go China on ebay have both 5" and 7" displays at 800x480 and both use the same 40 pin system and both have the SSD1963 so we could maybe think about a board that supports both? The 7" one however does not have the header in the center of the board $80 which would change the way a propeller board was designed. How much was yours?

    $50 including shipping for this one but it is a 34 pin header instead of 40 pins.

    $58 for this one with 40 pins but you would need to buy a 40 pin header

    $61 with a header soldered on

    I note these boards are all running from 3.3V so they are not going to be compatible with the 3.2" ones that run on 5V. So need a new design anyway...
  • average joeaverage joe Posts: 795
    edited 2013-02-18 17:12
    @ Dr A.
    I can't wait to see the new boards you're working on! They sound quite interesting.

    There is still a ton of things to get working *and perfected*. I finally got icons working, then broke BMPtoILI... Have not even tested fonts yet..

    The display I purchased is here : :
    $61 is still more expensive than the other displays. There's also other issues... With the increase in pixels, a full screen takes over half the RAM. This means the desktop needs to be wiped if we intend on loading a different full-screen image. I have a couple thoughts about this, but need to explore further before publishing the details. Then there's the fact it takes about 7 seconds to load the desktop background.

    The display required a small modification. Removed the resistor for backlight-enable and filled a solder bridge. The power pins are labeled 3v3 only, but runs off 5v just fine. Not sure about other displays, although if they have regulators should work. Several other 7" boards have a 40-pin header, but there seems to be a few different pin layouts.

    Gotta run! Much more soon
Sign In or Register to comment.