Re regulators, don't worry about switching regs if you don't want to. Any reg will be fine. There are several places on the board you can bring in regulated voltages from another place if you want to.
I got most of the components from futurlec, but they can take a couple of weeks to arrive and sometimes it is hard to find parts on their website that you know they sell.
I found a mistake on the board. I'm using P16 for the clock and I need to use P19 or higher. I didn't read the spec sheet closely enough I thought the data was loaded when the load went from low to high, but it isn't - see below.
These counters may be preset using the LOAD input. Presetting
of all four flip-flops is synchronous to the rising edge
of CLOCK. When LOAD is held LOW counting is disabled
and the data on the A, B, C, and D inputs is loaded into the
counter on the rising edge of CLOCK. If the load input is
taken HIGH before the positive edge of CLOCK the count
operation will be unaffected.
So some tracks are going to need to be cut and moved. I think it will be a matter of driving all the clocks from P19 instead of P16, and then driving the memory /RD from P16 instead of P19. I'll need to think about where to put the changes on the board.
addit - found a few more things on the board that are not quite right. Apart from swapping things above, I think the schematic is right though. Hmm - I might have to hold off posting any boards though. Maybe better to build this on a breadboard first?
Sorry I didn't notice the load line error. I guess I should have looked over the schematic a bit closer. I'll take another, closer, look at the schematic tonight.
I did decide to order regulators and all necessary components.
I think it might be a good idea to breadboard first. I always start here if possible. Cutting a few traces is not a huge deal to me, but I will leave this up to you. I've been working on the old ili driver and almost done with ram to hub and hub to ram transfers. I need to get a jump start on homework for next week, but after this is done I will continue working.
*edit*
Okay, I've been working on the driver and hit an issue. I'm looking at the datasheet for my hc counters and see max clock 25MHZ @ 4.5V, 5MHZ @ 2v. *I'm going to slow it down for the LS, but will be going full HC - 3.3V compatible* So. How should I guestimate the timing cycle? Any advice? Just start slow and speed it up till it won't run?
another edit
I've been working on the ram read and write in ASM. None of this is tested, but I'm trying to get a framework. I think this should be close.
DAT' First part tests ok'' +--------------------------------------------------------------------------+'' | Dracblade Ram Driver (with grateful acknowlegements to Cluso) |'' +--------------------------------------------------------------------------+org0
tbp2_start ' setup the pointers to the hub command interface (saves execution time later' +-- These instructions are overwritten as variables after start
comptr mov comptr, par' -| hub pointer to command
hubptr mov hubptr, par' | hub pointer to hub address
ramptr add hubptr, #4' | hub pointer to ram address
lenptr mov ramptr, par' | hub pointer to length
errptr add ramptr, #8' | hub pointer to error status
cmd mov lenptr, par' | command I/R/W/G/P/Q
hubaddr add lenptr, #12' | hub address
ramaddr mov errptr, par' | ram address
len add errptr, #16' | length
err nop' -+ error status returned (=0=false=good) ' Initialise hardware tristates everything and read/write set the pins
init mov err, #0' reset err=false=goodmovdira,zero ' tristate the pins
done wrlong err, errptr ' status =0=false=good, else error xwrlong zero, comptr ' command =0 (done)' wait for a command (pause short time to reduce power)
pause
' mov ctr, delay wz ' if =0 no pause' if_nz add ctr, cnt' if_nz waitcnt ctr, #0 ' wait for a short time (reduces power)rdlong cmd, comptr wz' command ?if_zjmp #pause ' not yet'decode command ' cmp cmd, #"Z"wz' Z moves command to the display from hub address, length timesif_zjmp #hubtodisplayCommand ' command format "DoCmd(Z,hub_address, unused, length) cmp cmd, #"Y"wz' Y moves data to the display from hub address, length timesif_zjmp #hubtodisplayData ' data format "DoCmd(Y, hub_address, unused, length)cmp cmd, #"R"wz' R = read block from external ram to hubif_zjmp #rdblock
cmp cmd, #"W"wz' W = write block from hub to external ramif_zjmp #wrblock
cmp cmd, #"C"wz' C moves a block of data from ram to the displayif_zjmp #extramtodisplay
' add new commands HERE ' cmp cmd, #"A" wz ' A moves 256 bytes from hub to external ram' if_z jmp #blockhubtoram' cmp cmd, #"B" wz ' B moves 256 bytes from external ram to hub' if_z jmp #blockramtohub' cmp cmd, #"E" wz ' convert 3 byte .raw format to 2 byte .ili format - hub to hub' if_z jmp #rawtoiliformat' cmp cmd, #"F" wz ' draw a transparent icon, pass two locations in hub ram and len = number of pixels' if_z jmp #drawiconcmp cmd, #"I"wz' initif_zjmp #init
' mov err, cmd ' error = cmd (unknown command)jmp #done
ram_open rdlong hubaddr, hubptr ' get hub addressrdlong ramaddr, ramptr ' get ram addressrdlong len, lenptr ' get lengthmov err, #5' err=5
ram_open_ret ret
hubtodisplayData ' send a block of data blocklen from hubaddr to the display (bypasses external ram)call #ram_open ' gets hubaddr and len (ignores ramaddress) call #setRShigh ' set pins for data output
:hubdisploop rdword Display, hubaddr ' copy word from hub, not needed ?add hubaddr,#2' add 2 to hub address changed for word alligned call #ilidisplayword ' send these bytes to the displaydjnz len,#:hubdisploop ' loop until donejmp #init ' set pins to tristate
hubtodisplayCommand call #ram_open ' gets hubaddr and len (ignores ramaddress)
:hubdisplayloop call #setRSlow ' set pins for Command outputrdword Display, hubaddr ' copy word from hubadd hubaddr,#2' add 2 to hub address changed for word allignedcall #ilidisplayword ' send these bytes to the display djnz len,#:data ' loop until donejmp #init ' set pins to tristate
:data call #setRShigh
rdword Display, hubaddr ' copy word from hubadd hubaddr,#2' add 2 to hub address changed for word allignedcall #ilidisplayword ' send these bytes to the display djnz len,#:hubdisplayloop ' loop until donejmp #init ' set pins to tristate
setRShigh movouta, PinsInit
movdira, DirsEnabled ' set rsHigh by tristate pin
setRShigh_ret ret
setRSlow movouta, PinsInit
movdira, DirsEnabled wz' set rsHigh by tristate pin muxnzdira, RSpin ' set rsLow by enabling pin
setRslow_ret ret
ilidisplayword ' pass data out, sends out to the displayadd Display, p2dpins wz'this add presets the data for control pins and primes WZ flag for mux operation movouta, Display 'then make pins = datamuxzdira,EnablePin 'make enable pin low mov timeout, #$f'set wait period
:wait1 djnz timeout, :wait1 'and wait muxnzdira, EnablePin 'make enable pin high
ilidisplayword_ret ret'*********************************************************************************************************************************** 'tests ok'---------------------------------------------------------------------------------------------------------'Memory Access Functions
rdblock call #ram_open ' get variables from hub variablescall #load_ram_add ' load first address into counters
rdloop call #read_memory_word ' read word from address into data_8wrword data_8,hubaddr ' write data_8 to hubaddr ie copy WORD to hubadd hubaddr,#1' add 1 to hub addressadd ramaddr,#1' add 1 to ram addresscall #inc_ram_address ' increment RAM addressdjnz len,#rdloop ' loop until donejmp #init ' reinitialise' write block from hub to external ram
wrblock call #ram_open
call #load_ram_add ' load first address into countersmovdira, P2RPins
wrloop rdword data_8, hubaddr ' copy word from hubcall #write_memory_word ' write word from data_8 to addressadd hubaddr,#1' add 1 to hub addressadd ramaddr,#1' add 1 to ram addresscall #inc_ram_address ' increment RAM address djnz len,#wrloop ' loop until donejmp #init ' reinitialise
load_ram_add
movouta, RamLoadPins wz'preset pins and clear z flag. pins still tri-stateaddouta, ramaddr 'move rammaddress onto busmovdira, RamLoadDirs 'and enable all pins 'wait here if needed?muxzouta, EnablePin ' make Enable Pin Low'wait here if needed?muxnzouta, EnablePin ' make Enable Pin High'wait?movdira, zero ' tri-state all pins'wait here if needed?
load_ram_add_ret ret
read_memory_word movouta, R2PPins ' preset pins for readmovdira, R2PDirs ' enable pinsadd timeout, RAMRDtimeout 'wait here if needed
:wait djnz timeout, #:wait
mov data_8, inaand data_8, #$FF' extract 16 bits
read_memory_word_ret ret
write_memory_word and data_8, lowWordMask ' ensure upper bytes=0add data_8, P2RPins ' add to P2E initPinsmovouta, data_8 wz' send it outmuxzouta, Cadd1Pin ' make 138 = RAMWRmuxzouta, EnablePin ' make ram WR LOWadd timeout, RAMWRtimeout 'set wait
:wait djnz timeout, #:wait 'and waitmuxnzouta, EnablePin ' make ram WR HIGH muxzouta, Cadd1Pin ' make 138 = COUNT
write_memory_word_ret ret
inc_ram_address add zero, #0wz'prime z flag muxnzouta, EnablePin 'make Enable Pin LOWmov timeout, countTimeout 'set wait
:wait djnz timeout, #:wait 'and waitmuxzouta, EnablePin 'make enable Pin High'and wait again? ' mov timeout, countTimeout 'set wait':wait djnz timeout, #:wait 'and wait
inc_ram_address_ret ret'extramtodisplay ' send a block of data blocklen from external memory ramaddress to the ILI9325 displaycall #ram_open ' gets ramaddr and len (ignore hubaddr) call #load_ram_add ' loads ram address for transfermovouta, R2DPins ' preset pins for R2D transfermovdira, R2DDirs ' enable pins'and wait if necessary?add zero, #0'prime z flag
ililoop muxnzouta, EnablePin ' make enable pin LOWmov timeout, #$f' set wait
:wait1 djnz timeout, #:wait1 ' and waitmuxzouta, EnablePin 'make enable pin HIGHmuxnzouta, Cadd0Pin ' set for ramcountcall #inc_ram_address ' and load next ram addressmuxzouta, Cadd0Pin ' set for lcd_wrmov timeout, #$f' set wait
:wait2 djnz timeout, #:wait2 ' and waitdjnz len,#ililoop ' loop until donejmp #init ' set pins to tristate
RAMRDtimeout long$0000_00FF
RAMWRtimeout long$0000_00FF
countTimeout long$0000_00FF
lowWordMask long$0000_ffff'pin settings
EnablePin long%00000000_00000010_00000000_00000000
RSPin long%00000000_00000001_00000000_00000000
LoadPin long%00000010_00000000_00000000_00000000
RamLoadPins long%00001100_01000010_00000000_00000000
RamLoadDirs long%00001111_11100010_11111111_11111111
R2PDirs long%00001101_11100010_00000000_00000000
P2RDirs long%00001001_11100010_00000000_00000000
P2RPins long%00001110_01000010_00000000_00000000
R2PPins long%00000010_01000010_00000000_00000000
R2DPins long%00000000_01100011_00000000_00000000
R2DDirs long%00000101_11100011_00000000_00000000
p2dpins long%00001000_01100000_00000000_00000000' propToDisplay enable pin low, but tristate, primed for lcd transfer
PinsInit long%00001001_01100010_00000000_00000000'pins Inital state, BUS = Prop -> RAM, Not RamRD, BusDisabled, enable pin high
DirsEnabled long%00001001_11100000_11111111_11111111'' (R4Fh) (POR = 0000h)
CAdd0Pin long%00000000_00100000_00000000_00000000
Cadd1Pin long%00000000_01000000_00000000_00000000
Cadd2Pin long%00000000_10000000_00000000_00000000
timeout res1
Display res1fit
I will keep updating this until it works, I just wanted to get a start so you could make suggestions. Also, here's the schematic
I flipped a quarter and it came up tails, so I started working on a new schematic. I updated to 19 bit address line, and your ram chips. I also added 2 - `374s to save 4 prop pins and add 12 GPOs. Un-buffered access to the 19 prop pins and 1 control pin are also provided. Two audio outs as well as midi I/O round out the connections. I also provided leds on p30 and p31 as you have. Should help debugging? There are a few errors I am aware of. Resistor values are incorrect for audio outs. I am still debating adding 5v reg. For those without midi devices, you can use the midi i/o for a ps2 keyboard? Or maybe even usb?
I did not want to use the inverters, but couldn't think of an easier way. Let me know what you think!
*edited*
I found more issues. I forgot to remove a few resistors from the lcd lines. I am also thinking about adding a 4 pin jumper for midi I/O or PS2 port.
Looking good. Let me know how it goes on a breadboard. Are you still running the ram chips from 5V?
I got routines working tonight to transfer data from hub to ram and ram to hub
PUBHubToRam(RamAddress,Number) | i' send data from hub to ram in a block
Load161(RamAddress) ' load all the 161 chips with the start value
i := 0repeat Number
OUTA &= %11111111_11111111_00000000_00000000' clear for outputOUTA |= rambuffer[i] ' send out a word to P0-P15
WR_Low ' write to ram
WR_High ' toggle ram write
Clock161_Low ' toggle clock
Clock161_High
i += 1' increment iPUBRamToHub(RamAddress, Number) | i' send data from ram to hub in a block
Load161(RamAddress) ' load all the 161 chips with the start value
i := 0DIRA &= %00001111_11111111_00000000_00000000' set P0-P15 as inputsrepeat Number
RD_Low ' read pin low
rambuffer[i] := INA' get the data
RD_High
Clock161_Low ' toggle clock
Clock161_High
i += 1' increment iDIRA |= %00000000_00000000_11111111_11111111' restore P0-P15 as outputs
So - move data from SD card to propeller, prop to external ram, external ram back to prop, and external ram to the display. This last one is where the fast refresh works with 30ms to do a screen. It is super simple in spin and so will easily translate over to pasm
PUBRamToDisplay(RamAddress,Number)' send n words to the display after sending a Draw command
Load161(RamAddress) ' load all the 161 chips with the start value
ILI_RS_High ' RS high for sending data
RD_Low ' memory read lowDIRA &= %00001111_11111111_00000000_00000000' set P0-P15 as inputs so no data clash with propeller (prop ignores these pins) repeat Number
ILI_WR_Low ' send out the data
ILI_WR_High
Clock161_Low ' toggle clock
Clock161_High
RD_High ' memory read highDIRA |= %00000000_00000000_11111111_11111111' restore P0-P15 as outputs
This little bit of code fills the screen from the ram with 76800 pixels (15% of the ram capacity)
Draw(0,0,239,319) ' dump out 76800 words to the display = a full screen
RamToDisplay(0,76800)
and the speed in spin is 5.5 seconds, which I think compares favorably with the previous speed around 9 seconds. This is going to be very fast in pasm.
This 161 driver is brilliant!
Full program:
'' ILI9325 driver using the Touchblade161 design for faster ram to display transfers'' James Moxham 2012CON_clkmode = xtal1 + pll16x' use crystal x 16_xinfreq = 5_000_000
_1ms = 1_000_000 / 1_000' Divisor for 1 ms ' pins' P24 = audio out' 25,26,27 138 one of 8 decoded, active low' 0=000 = SPI touchscreen input, keyboard, TV VGA enabled' 1=001 = Load counter' 2=010 = Memory transfer - P0-P15=bus, P19=161_clk, P17 = ILI_WR, P18=ILI_RS, P16= Ram_RD, P20=Ram_WR,P21-23 = SD card' 3=011 = ILI Reset' 4=100 = Digital output (8 bits to a 574 latch)' 5=101 = spare' 6=110 = spare' 7=111 = startup (all above deselected)OBJVARlong orientation
long curx, cury
long clkcycles ' for the delay routinePUBMain
curx :=0
cury :=0
PinsHigh
start_ram ' start the cog driver
MemoryTransferSelect ' select 138 and set control pins
Start_ILI9325 ' start the display
HelloWorld ' Bootup message
rambuffer[0] :=$AA55' some random word values
rambuffer[1] :=$07FF
rambuffer[2] := %00000111_11100000' green pixels
rambuffer[3] := %00000111_11100000
rambuffer[4] := %11111000_00000000' red pixels
rambuffer[5] := %11111000_00000000
rambuffer[6] := %11111000_00000000
HubToRam(0,7) ' ramaddress, number. Uses rambuffer (word array) up to 256
rambuffer[1] := 0' clear the value for debugging
RamToHub(0,7) ' read data back
MemoryTransferSelect ' reselect 138 for display output for debugging
hex(rambuffer[1],4)
Draw(99,95,108,104) ' draw a little black squarerepeat100
Pixel(0)
Draw(100,100,106,100) ' display pixels
RamToDisplay(0,7) ' dump out from ram to displayrepeatPUBRamToDisplay(RamAddress,Number)' send n words to the display after sending a Draw command
Load161(RamAddress) ' load all the 161 chips with the start value
ILI_RS_High ' RS high for sending data
RD_Low ' memory read lowDIRA &= %00001111_11111111_00000000_00000000' set P0-P15 as inputs so no data clash with propeller (prop ignores these pins) repeat Number
ILI_WR_Low ' send out the data
ILI_WR_High
Clock161_Low ' toggle clock
Clock161_High
RD_High ' memory read highDIRA |= %00000000_00000000_11111111_11111111' restore P0-P15 as outputs PUBHubToRam(RamAddress,Number) | i' send data from hub to ram in a block
Load161(RamAddress) ' load all the 161 chips with the start value
i := 0repeat Number
OUTA &= %11111111_11111111_00000000_00000000' clear for outputOUTA |= rambuffer[i] ' send out a word to P0-P15
WR_Low ' write to ram
WR_High ' toggle ram write
Clock161_Low ' toggle clock
Clock161_High
i += 1' increment iPUBRamToHub(RamAddress, Number) | i' send data from ram to hub in a block
Load161(RamAddress) ' load all the 161 chips with the start value
i := 0DIRA &= %00001111_11111111_00000000_00000000' set P0-P15 as inputsrepeat Number
RD_Low ' read pin low
rambuffer[i] := INA' get the data
RD_High
Clock161_Low ' toggle clock
Clock161_High
i += 1' increment iDIRA |= %00000000_00000000_11111111_11111111' restore P0-P15 as outputs PUBLoad161(RamAddress)
Select138(7) ' deselect previous 138 valueDIRA |= %00000000_00011111_11111111_11111111' P0-P18 enabled for output plus P19,P20OUTA &= %00001110_11111000_00000000_00000000' preserve previous values but set A0-18 lowOUTA |= RamAddress ' output address to the 161 chips
Clock161_Low ' clock low
Select138(1) ' 161 load low
Clock161_High ' load in valueOUTA |= %00000000_11111111_00000000_00000000' set P16-P23 high prior to changing 138
Select138(2) ' 161 load high and back to mem transferPUBClock161_LowOUTA &= %11111111_11110111_11111111_11111111' P19 lowPUBClock161_HighOUTA |= %00000000_00001000_00000000_00000000' P19 highPUBWR_LowOUTA &= %11111111_11101111_11111111_11111111' P20 lowPUBWR_HighOUTA |= %00000000_00010000_00000000_00000000' P20 highPUBRD_LowOUTA &= %11111111_11111110_11111111_11111111' P16 lowPUBRD_HighOUTA |= %00000000_00000001_00000000_00000000' P16 high PUBPinsHighDIRA := %00001111_11111111_11111111_11111111' enable all pins as outputsOUTA := %00001110_11111111_11111111_11111111' all except P24 audio out are high PUBMemoryTransferSelect
Select138(2) ' enable memory transfer groupDIRA |= %00001110_11111111_11111111_11111111' Pins all as outputsOUTA |= %00000000_11111111_00000000_00000000' all control pins high PUBSelect138(n)' pass n=0 to 7
n := n<<25' shift left so pins 25,26,27DIRA |= %00001110_00000000_00000000_00000000' enable these pins for outputOUTA &= %11110001_11111111_11111111_11111111' mask 3 pins lowOUTA |= n ' send outPUBClearscreen
Draw(0,0,239,319) ' clear the screen - slow spin versionrepeat76800
Pixel($0000)
PUBHelloWorld' use propeller font in the rom for bootup messages when debugging sd cards
Propfont_string(string("Hello World")) ' string to sendPUBPropfont_string(stringptr)'print at curx,curyrepeatstrsize(stringptr)
Propfont_out(byte[stringptr++])
crlf
PUBcrlf
curx := 0
cury += 32' new line at end of stringif cury >319' bottom of screen so new screen
curx:=0
cury:=0PUBPropfont_out(ascii) | address,pixels
Draw(curx,cury,curx+15,cury+31) ' location to start drawing
address := $8000 + (ascii >> 1) << 7' get rom addressrepeat32' 32 rows per character, split in two parts
pixels := long[address] ' get rom font data
pixels := pixels >> (ascii & 1) ' shift for odd charactersrepeat16' 16 columnsif pixels & 1
Pixel(%00000111_11100000) ' foreground color RRRRRGGG_GGGBBBBBelse
Pixel(%00000000_00000000) ' background color
pixels := pixels >> 2' alternate pixels interleaved so shift 2
address += 4
curx +=16if curx >239' new line
crlf
PUBStart_ILI9325' pass orientation true = portrait, false = landscape
ILI_Reset_High
pause1ms(5)
ILI_Reset_Low
pause1ms(5)
ILI_Reset_High
ILI_CS_High
ILI_RD_High
ILI_WR_High
pause1ms(5)
ILI_CS_Low
' ************* Start Initial Sequence **********
ILIcmd($00E5,$78F0) ' set SRAM internal timing
ILIcmd($0001,$0100) ' set SS and SM bit 0001 0100 portrait
ILIcmd($0002,$0700) ' set 1 line inversion
ILIcmd($0003,$1030) ' set GRAM write direction and BGR=1. $0003 $1030
ILIcmd($0004,$0000) ' Resize register
ILIcmd($0008,$0207) ' set the back porch and front porch
ILIcmd($0009,$0000) ' set non-display area refresh cycle ISC[3:0]
ILIcmd($000A,$0000) ' FMARK function
ILIcmd($000C,$0000) ' RGB interface setting
ILIcmd($000D,$0000) ' Frame marker Position
ILIcmd($000F,$0000) ' RGB interface polarity ' *************Power On sequence ****************//
ILIcmd($0010,$0000) ' SAP, BT[3:0], AP, DSTB, SLP, STB
ILIcmd($0011,$0007) ' DC1[2:0], DC0[2:0], VC[2:0]
ILIcmd($0012,$0000) ' VREG1OUT voltage
ILIcmd($0013,$0000) ' VDV[4:0] for VCOM amplitude
ILIcmd($0007,$0001)
pause1ms(50) ' Dis-charge capacitor power voltage
ILIcmd($0010,$1090) ' 1490//SAP, BT[3:0], AP, DSTB, SLP, STB
ILIcmd($0011,$0227) ' DC1[2:0], DC0[2:0], VC[2:0]
pause1ms(50) ' delay
ILIcmd($0012,$001F) ' 001C// Internal reference voltage= Vci;
pause1ms(50) ' delay
ILIcmd($0013,$1500) ' $1000//1400 Set VDV[4:0] for VCOM amplitude 1A00
ILIcmd($0029,$0027) ' $0012 //001a Set VCM[5:0] for VCOMH //$0025 0034
ILIcmd($002B,$000D) ' Set Frame Rate 000C
pause1ms(50) ' delay
ILIcmd($0020,$0000) ' GRAM horizontal Address
ILIcmd($0021,$0000) ' GRAM Vertical Address ' ----------- Adjust the Gamma Curve ----------//
ILIcmd($0030,$0000)
ILIcmd($0031,$0707)
ILIcmd($0032,$0307)
ILIcmd($0035,$0200)
ILIcmd($0036,$0008)
ILIcmd($0037,$0004)
ILIcmd($0038,$0000)
ILIcmd($0039,$0707)
ILIcmd($003C,$0002)
ILIcmd($003D,$1D04)
' ------------------ Set GRAM area ---------------//
ILIcmd($0050,$0000) ' Horizontal GRAM Start Address
ILIcmd($0051,$00EF) ' Horizontal GRAM End Address
ILIcmd($0052,$0000) ' Vertical GRAM Start Address
ILIcmd($0053,$013F) ' Vertical GRAM Start Address
ILIcmd($0060,$A700) ' Gate Scan Line
ILIcmd($0061,$0001) ' NDL,VLE, REV
ILIcmd($006A,$0000) ' set scrolling line ' -------------- Partial Display Control ---------/
ILIcmd($0080,$0000)
ILIcmd($0081,$0000)
ILIcmd($0082,$0000)
ILIcmd($0083,$0000)
ILIcmd($0084,$0000)
ILIcmd($0085,$0000)
' //-------------- Panel Control -------------------//
ILIcmd($0090,$0010)
ILIcmd($0092,$0600)
ILIcmd($0007,$0133) ' 262K color and display ON
ChangeOrientation(true) ' default to portraitPUBChangeOrientation(n)' pass true = portrait or false = landscape, changes global variable orientation in this object
orientation := n
if orientation
ILIcmd($0001,$0100) ' set SS and SM bit 0001 0100 portrait
ILIcmd($0003,$1030) ' set GRAM write direction and BGR=1. $0003 $1030 else
ILIcmd($0001,$0000) ' set SS and SM bit 0001 0000 landscape
ILIcmd($0003,$1038) ' landscape $1028 = original but 1038 is correct - not mirror imagePUBDraw(x1, y1, x2, y2)' sets the pixel to x1,y1 and then fills the next (x2-x1)*(y2-y1) pixelsifnot orientation ' landscape mode so swap x and yresult :=x1 ' swap x1 and y1
x1 := y1
y1 := resultresult := x2 ' swap x2 and y2
x2 :=y2
y2 := result
ILIcmd($0050,x1)
ILIcmd($0052,y1)
ILIcmd($0051,x2)
ILIcmd($0053,y2)
ILIcmd($0020,x1)
ILIcmd($0021,y1)
Lcd_Write_Com($0022)
PUBPixel(pixelcolor)' send out a pixel
Lcd_Write_Data(pixelcolor)
PUBpause1ms(period)'' Pause execution for period (in units of 1 ms).
clkcycles := ((clkfreq / _1ms * period) - 4296) #> 381' Calculate 1 ms time unitwaitcnt(clkcycles + cnt) ' Wait for designated timePUBhex(value, digits)'' Print a hexadecimal number
propfont_out("O")
propfont_out("x")
value <<= (8 - digits) << 2repeat digits
propfont_out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
crlf
PRIILIcmd(c,d)' instruction in one method
Lcd_Write_Com(c) ' send out a word
Lcd_Write_Data(d)
PRILcd_Write_Com(ILIlong)
ILI_RS_low
LCD_Writ_Bus(ILIlong)
PRILcd_Write_Data(ILIlong)
ILI_RS_High
LCD_Writ_Bus(ILIlong)
PRILCD_Writ_Bus(ILILong)'ILILong &= %00000000_00000000_11111111_11111111 ' mask to a word. Not needed if care taken always to send a word valueOUTA &= %11111111_11111111_00000000_00000000' set P0-P15 to zero ready to OROUTA |= ILILong ' merge with the word to output
ILI_WR_Low ' send out the data
ILI_WR_High
PRIILI_RS_LowOUTA &= %11111111_11111011_11111111_11111111' P18 lowPRIILI_RS_HighOUTA |= %00000000_00000100_00000000_00000000' P18 highPRIILI_RD_Low' pulled high in hardware, not used PRIILI_RD_HighPRIILI_WR_LowOUTA &= %11111111_11111101_11111111_11111111' p17 lowPRIILI_WR_HighOUTA |= %00000000_00000010_00000000_00000000' p17 highPRIILI_CS_Low' not used as setting 138 to %010 does thisPRIILI_CS_HighPRIILI_RESET_Low' reset low
Select138(3) ' reset lowPRIILI_RESET_High
Select138(2) ' 138 back to memselect DAT
sdbuffer byte$0[512] ' 512 byte buffer for sd card interface
rambuffer word$0[256]
'************************** Cog driver for the 16 bit ILI9325 screen *********************VAR' communication params(5) between cog driver code - only "command" and "errx" are modified by the driverlong command, hubaddrs, ramaddrs, blocklen, errx, cog ' rendezvous between spin and assembly (can be used cog to cog)' command = R, W, H I,D etc =0 when operation completed by cog' hubaddrs = hub address for data buffer' ramaddrs = ram address for data ($0000 to $FFFF)' blocklen = ram buffer length for data transfer' errx = returns =0 (false=good), else <>0 (true & error code)' cog = cog no of driver (set by spin start routine)PUBstart_ram : err_' Initialise the Drac Ram driver. No actual changes to ram as the read/write routines handle this
command := "I"
cog := 1 + cognew(@tbp2_start, @command)
if cog == 0
err_ := $FF' error = no cogelserepeatwhile command ' driver cog sets =0 when done
err_ := errx ' driver cog sets =0 if no error, else xx = error codePUBstop_ramif cog
cogstop(cog~ - 1)
PUBDoCmd(command_, hub_address, ram_address, block_length) : err_' Do the command: R, W, N, F, H,I,D
hubaddrs := hub_address ' hub address start
ramaddrs := ram_address ' ram address start
blocklen := block_length ' block length
command := command_ ' must be last !!' Wait for command to complete and get statusrepeatwhile command ' driver cog sets =0 when done
err_ := errx ' driver cog sets =0 if no error, else xx = error codeDAT'' +--------------------------------------------------------------------------+'' | Dracblade Ram Driver (with grateful acknowlegements to Cluso) |'' +--------------------------------------------------------------------------+org0
tbp2_start ' setup the pointers to the hub command interface (saves execution time later' +-- These instructions are overwritten as variables after start
comptr mov comptr, par' -| hub pointer to command
hubptr mov hubptr, par' | hub pointer to hub address
ramptr add hubptr, #4' | hub pointer to ram address
lenptr mov ramptr, par' | hub pointer to length
errptr add ramptr, #8' | hub pointer to error status
cmd mov lenptr, par' | command I/R/W/G/P/Q
hubaddr add lenptr, #12' | hub address
ramaddr mov errptr, par' | ram address
len add errptr, #16' | length
err nop' -+ error status returned (=0=false=good) ' Initialise hardware tristates everything and read/write set the pins
init mov err, #0' reset err=false=goodmovdira,zero ' tristate the pins
done wrlong err, errptr ' status =0=false=good, else error xwrlong zero, comptr ' command =0 (done)
pause
rdlong cmd, comptr wz' command ?if_zjmp #pause ' not yet' decode commandcmp cmd,#"M"wz' move a block from ram to the displayif_zjmp #moveblock
cmp cmd, #"I"wz' initif_zjmp #init
mov err, cmd ' error = cmd (unknown command)jmp #done
'---------------------------------------------------------------------------------------------------------
ram_open rdlong hubaddr, hubptr ' get hub addressrdlong ramaddr, ramptr ' get ram addressrdlong len, lenptr ' get lengthmov err, #5' err=5
ram_open_ret ret
Moveblock ' uses ramaddr and len' OUTA := address ' address is not latched - this is where the speed is' OUTA &= %11111111_10111111_11111111_11111111 ' ILI write low' OUTA |= %00000000_01000000_00000000_00000000 ' ILI write high' address++ ' increment addressmovdira,direction ' set P0-P23 as outputs call #ram_open ' get ramaddr and lenor ramaddr,pin22 ' start with pin 22 high
Moveblock_loop movouta,ramaddr ' send out the address valueandnouta,pin22 ' set pin 22 loworouta,pin22 ' set pin 22 highadd ramaddr,#1' increment ram addressdjnz len,#moveblock_loop
jmp #init
halt jmp #halt
' ************************ Variables ******************************
delay long80' waitcnt delay to reduce power (#80 = 1uS approx)
Zero long%00000000_00000000_00000000_00000000' for tristating all pins
pin22 long%00000000_01000000_00000000_00000000
direction long%00000000_11111111_11111111_11111111fit496
Wonderful! I am still running ram chips @5v. I am debating the switch to 3.3v, but looking at the timings I think 5v will be best. My new board will allow for either voltage with the change of a jumper. Please take a close look at the new schematic and let me know if you see any errors or room for improvement. I will be ordering a short run of boards as soon as I figure out how to do a large layout with the free version of eagle. I plan on sending you one when I get them done.
Here's the schematics, and a basic idea for a layout. I am unable to layout a board because I am using eagle light. If you would do me a HUGE favor and throw a layout together, I will send you one when they're printed.
Can you repost that .jpg a bit bigger - I can see the chips but not the text that goes with them. (I added a .pdf 'printer' to my computer which you can then print to from any program. I think there are a number of these free pdf printers around. The pdf files can be zoomed better than a .jpg)
Re getting boards made I wonder if 3.3V memory chips would be better as there would be an extra cost with the board space required for the resistors?
The rar archive contains the schematic, png copy of the schematic as well as a basic idea for the layout. I will start printing as .pdf from now on, as per your advice.
Concerning switching to 3.3v, I guess it's really a trade-off between speed and board footprint. I'm not sure how much space those resistors would add, nor how much more it would cost. I am also unsure what difference running @5v will do to clock speed. The 161's are rated @ 4.5 and 2 volts supply. Max frequency @2v is 6mhz, at 4.5v it's 30mhz. I'm wondering if this will help speed transfers from hub to ram and ram to hub. This will not improve ram to display writes, but should double working frequency? I would be interested to see what the max you're clocking your boards at. If it's close to the 30mhz side then I would say the switch to 3.3v would be ok. If it's under half I think the 5v would be best.
If we can get the cost of a 3.3-5v board under $20 bucks, then it would be worth a short run to me.
*edit*
JP2 could be removed, and ext_out replaced with a single pin or this pin could be added to FPouts. This would save a bit of board space.
The rar archive contains the schematic, png copy of the schematic as well as a basic idea for the layout. I will start printing as .pdf from now on, as per your advice.
Yes, sorry about that - not able to extract things from the work computer. I'll take a look when I get home.
Thanks for the hints re the clock freq. Hopefully over the next few days I'll get a chance to push it all to pasm speeds. Start with some NOPs and then remove them one by one. The loop to move data from ram to display is only 4 pasm instructions plus one DJNZ so we shall see how fast it can go. I suspect the propogation of the overflow through the five 161 chips might be a limiting factor. Shouldn't matter though - 30ms vs 60ms for a screen refresh would not be noticable.
I'd still hold re getting boards made. Still a few things to test out. My working board is becoming a mess of wire wrap links and drilled out vias but it is helping refine what the final working board is going to look like. I know with what we have that this is going to be quick. I think we can get it to 'ipad' speeds - touch the display and something happens instantly. Compared with my android pandapad, I can say we have already moved beyond 'android speed' for some things. (especially bootup time). All very exciting.
I think the ram voltage is key with getting the hw as fast as possible. I agree that 30ms vs 60ms screen refresh is not perceivable, but doubling transfer speed to and from ram will be huge for me. Especially considering I will be using the 19 pins for quite a bit more than just transferring to screen and ram. My schematic allows reads from the screen, which I plan on using to dump a screen to Sd card. I also plan on being able to use p0-18 WHILE transferring from ram to display. I'm working on output expansion boards in the next few days. I'm planning several different modules, but the first to be completed will be * 2 - 4 x 40 LCD screens with 16 rotary encoders with push buttons, 16 leds and some buttons. *
I apologize for being antsy to print boards, but I do not have enough room on the breadboards I have to put this together. Don't want to buy ANOTHER board, but just might. I'm ordering parts REAL soon, having larger ram will be nice.
I totally agree that we are moving beyond android speeds. I switched back to my DUMB OLD hardware to work on Midi implementation, as well as put the finishing touches on my guitar switcher. I added mono audio out and midi i/o. Have not tested either because I'm trying to get the screen working again. I don't know what I did, but I messed something up.
I found the problem a little while ago. The wire on the ribbon cable for pin2 had broke at the solder joint with the propRPM board. This is the second wire I've had to fix. That's what happens when you ghetto rig.
So I was just looking over the datasheet for the 161's again. Found a neat little formula for cascaded counting.
1/ (CP to TC prop. delay + TE to CP setup +TE to CP hold) = about max frequency
So for my figuring from the datasheet, for 2v operation.
1 / (185 + 50 + 0) = about 4MHZ
This is a long way from 21MHZ spec'd @ 4.5V. I know we're not running @2v, but 3.3. Not sure how this scales across, but it will be interesting to see your results. Now back to making new code work on old hardware. *headache*
*edited*
I just flashed on an idea to save some board space for the PropERMidi board. Move the resistors for the lcd screen to a board that stands between the two. Not the most elegant solution, but a solution nonetheless.
Re designs, I am working tonight on the SD driver and looking at the code out there, eg Kye's driver, it really does make things a lot simpler to devote 4 dedicated prop pins to the SD card. I had devoted P21-P23 with the /CS line decoded elsewhere but it will mean customising Kye's driver and I'd rather keep it as the standard version.
So I'm going to steal P24 which is the audio output for /CS and then for audio, borrow P29 which is the eeprom data line.
Schematic attached.
I've got some spare breadboards - I'll post them to you tomorrow.
Dedicated sd pins makes things easier by far. I was able to get fsrw going with minor adjustments. On my HW 3.4, I used a decoded /cs line and passed the address of the enable pin for this line. Then before doing an sd transfer, I set the address before calling. It works, but there are problems with this. I have thought about using locks to control access to the demux lines. This will use a few clock cycles, but should provide easy, safe sharing of the demux among cogs.
Yes 4 lines just for SD card makes things easier. I'm mulling over ways of running Catalina at the same time. Instead of using the 3 pins to decode a 138, use a MCP 23008 on the I2C bus, then take 3 of those pins and decode to a 138. That frees up 3 prop pins that could be used for external SPI memory (or even more cunning things like decoding a MCP23016 or two and feeding the data via I2C.) Terribly slow compared with parallel ram, but speed does not matter so much with C programs that use caching. I might post over on the Catalina thread about this.
Also for audio, I might use some lower number pins rather than P29, and then use two pins and get stereo. Kye's original SD driver contained a wav player and it would be cool to have a music player as one of the touchscreen icons.
In a general sense, once all the prop pins have been used to move pictures around from SD card to ram to the screen, that part can go to sleep and there are now a lot of free propeller pins for MIDI and other i/o.
Hey Doc, how's the project coming? Just one quick question, what do you think about doing a left-shift every bus transaction? Would this waste too many clock cycles or do you think we could fit this in? I've been thinking about using the first 4 pins for Audio and Midi I/O.
Project slowly getting there. SD card working, touchscreen working. Display is working in Spin and now porting it over to pasm. I'm about half way through that at the moment.
I'm not sure about left shifting. It isn't just the speed, it is also whether there are enough pins. The way I am doing things, once a picture has been sent to the screen, P0-P20 are free. In practice that would mean that if you want to play a song, you can't update the screen at the same time. But you can be polling for the screen being touched. There is a potential solution though - instead of decoding P25-P27 through a 138, use a MCP23008 on the I2C bus.
Midi is a bit like RS232, right? In which case, outputs can be pins that you can enable when you need them. Inputs on the other hand need dedicated pins.
So maybe we can free up P25-P27, use two for audio, one for Midi IN, and then intermittently enable another prop pin for midi OUT (ie you can only output if the screen is not being updated).
Eh, it sounds like my idea may have taken me further from the solution. Two propeller chips are sounding better and better. One for the screen, one for the sound module. If this is the case, we could ditch midi and audio on the controller. That would free 4 pins, and chip to chip communication would be done through EEPROM pins? I don't want to mess with the programming pins, but they could be re-purposed for midi *or something else?* later. I still think I will need that `245 since I would very much like to use the 19 pins while transferring from ram to display. I have ALL SORTS of plans for these pins actually.
Midi is quite a lot like 232. 7-bit asynchronous-serial, inverted, at 31.25k? I can't remember the number exactly. The spec also uses opto-isolators to combat ground loops. Not too big of a deal. The only reason my design requires CONSTANT midi in AND OUT is because I plan on doing Midi Time Code to Midi Clock conversion and vice versa. Not a feature I will be using all the time, but it will come in VERY handy when I do need it .
Hit the reset button, it boots into a simple text display running from the propeller ROM to display "SD". If the SD card works, it loads a font and displays a message. And then it reads a picture off the SD card and displays it.
Unzip the file and put the .ili picture and the .ifn font file on the SD card.
There was a fair bit of recoding - everything changed from big-endian to little-endian. Lots of pasm code to rewrite.
But the 161 concept is sound - it is (surprisingly) faster to have 5 external counter chips than it is to use the propeller's internal counters.
The code to update the display from ram did not need any NOPs or delays. It is just 5 pasm instructions to send two bytes.
ramtodisplay_loop andnouta,maskP17 ' ILI write loworouta,maskP17 ' ILI write highandnouta,maskP19 ' clock 161 loworouta,maskP19 ' clock 161 highdjnz len,#ramtodisplay_loop
76800 words = 153600 bytes, transferred in 30ms = 5.12 megabytes per second = 40.96 megabits per second.
WOW! Lemme repeat. WOW. 40.96 megabits per second is very very nice. I'll do the math but this should work quite well. I received my parts today, but decided to wait till after the expo to play with this. There's too much to work on right now, and not enough time. I pulled everything out of the project box because the inside was looking quite gross. I'm stripping the inside to bare metal and will rattle can quickly. Then put everything back together with version 3.4.2 hardware *my old pin for pin hardware with midi and audio* with some slight adjustments. Also quite a bit of coding left. I will not be working on any "throw away" code *drivers for 3.4.2 have a couple bugs, nothing major.* I can't wait to get working on the 161 based board, and I am getting close to a proposed schematic.
Keep up the great work!
I sent you a breadboard and some chips - should arrive next week. It is a large breadboard so you should be able to get all the project on one board.
I think you started off with a spin version that took 9 seconds to refresh the screen. So we are just under 300x faster than that. I've very pleased that there were no problems with the overflow delays through the 161 chips. Your circuit is so simple but so clever!
One nice thing about these fast screen refreshes - you can get on with other things like making music without having to worry about the screen so much.
I need to think about icons. The previous code used .raw files with RGBA where A is a transparency layer. I takes longer to process on the fly. I am thinking that when you load an icon, take the background where it is going to go and store that in a file and combine it with the icon file so that when you re-display that icon it draws the background at the same time. So icon files are two bytes per pixel not four, and there is a separate transparency file. It means you can't move icons so easily, but generally they stay in the same place anyway. Should speed up icon refreshes about 100x so I think it is worth it.
Have a look at how Microsoft did icons for Windows. Basically instead of an Alpha layer, they did chroma keying -- a special color is designated as "transparent" and you avoid replacing the background where that color is.
Thank you SO much! 300x is a HUGE improvement! To be honest, the credit goes to whoever came up with the idea of using a counter in the first place. The block transfer thingy you had on one of your pdf's made me think why not use 161's. Once again the idiot savant in me shines through!
Transparency is very nice, I've had some issues because I have not programmed anything for that. I don't see moving icons as too big of a deal. As long as we can define a decent sized character and move that easily *remember the old faders? gotta finish that eventually!*
G2G, Thank you SO SO SO much!
Joe
*edit*
I've been thinking about a screen designer. There are many ways to go, but my initial efforts playing with the fader idea were slow and laborious. A bank of custom, system characters will be needed. This includes transport controls such as play, pause, stop, FF, and RW. I HAD example layouts in PF, but lost these due to stupidity. They were very slow to draw since they used multiple characters. This will work WAY better and be WAY faster
Also, you need a name for your current board. Eurocard_Touchscreen_161 is too long I like "Euro-Touch++" I will examine it a few more times but it looks quite nice. Perfect for most Touch applications!
Playing around with images. Drawing a screen is so fast that it is ok to spend half a second doing a transfer from a standard file format. I took a picture off google images, ran it through paint shop pro, rotated it 90 degrees (not necessary if you reconfig the screen for landscape) resized it to 240x320 and saved it as a .raw file which is a standard RGB 3 bytes per pixel. Then convert with this little routine:
PUBRawPicture | i' take a standard RGB .raw file and convert to two byte RRRRRGGGGGGBBBBB format and fill memory
fat.openfile(string("synth.raw"),"R") ' a .raw file 240 wide, 320 high
i := 0repeat600
fat.readdata(@sdbuffer,384) ' 240x320=76800 bytes x3
docmd("E",@sdbuffer,@rambuffer,128) ' convert to 2 byte
HubToRam(i,128) ' send to external ram
i += 128' increment external ram counter
fat.closefile ' close file
DisplayPicture ' display the picture
Photo of this displaying "synth.raw"
This is what we need for audio - but maybe sliders might be better than circular knobs? Easier to use with a touchscreen?
You know that is the one problem I have been mulling over. Even the faders are a bit difficult to control. Faster screens mean drag n drop faders will be possible now, but accurately setting during live performance might be difficult. I would like at least 1 rotary encoder and probably a minimum of 8 *since I've had 3 of my friends say they think 8 minimum. A stylus will be a big improvement too!
I sent you a breadboard and some chips - should arrive next week. It is a large breadboard so you should be able to get all the project on one board. ...
Is there a PCB available? If so I would like to have one for doing a software reference design for this type of hardware. I've been thinking about this 161 load and strobe idea a long time like used int NES cartridges, but have been too busy to act on it. It would be nice to use and support an existing hardware design before making my own.
Dr Acula should have the schematic just about perfected. I'm not sure how many mods are needed for the boards he printed but if they are as extensive as he suggested, we might need a re-print. I will be supporting his hardware since I will be using modified versions of his low-level code. I need to look at the printed boards vs new schematic before I give the nod this time. If I would have been really THINKING about using the board as opposed to just looking it over, I would have caught one mistake. I am sorry about that again! Hopefully another run of boards will be made soon. I'm sure a few people will be interested even if they decide to use them purely for the ram.
I'm confused with the 74161 part of the schematic.
Ripple Carry Out "RCO" transitions low to high when Q outputs go from X to $F.
How can you guarantee that the next "nibble" counter is 0 while the first stage counter is $F?
That is: if you load $0000E to 5 counters and strobe the clock once, you want to get $0000F. Then strobe again to get $00010.
So the sequence you want is : load $0000E, strobe one gets $0000F, strobe two gets $00010.
This seems to happen instead: load $0000E, strobe one gets $0001F, strobe two gets $00010.
What really happens? Don't you need an inverter on the RCO for clocking the next stage?
It's ok, these chips can be a bit confusing. Pay close attention to the operation of load. That's what got Drac the first time. He was worried about propagation delays and the like when these things seem to work quite well. One more piece of advice, Dr Acula's very nice design keeps all chips at 3.3v. If you look at the datasheets, they are quite de-rated at 2 volts. I'm sure 3.3 is quite better, but 5v seems best for super-high speed operation. Plus 5v tolerant ram is less expensive than 3v. I plan on using 5v and some additional circuitry but need to actually try a few things before I commit. My thread has the most recent schematic I've written. It is not done and changes are small at this point. The inverter on the reset line is going away and getting replaced with an transistor - inverter. LCD wr/rd will be hooked up to Function Register. '374 http://forums.parallax.com/showthread.php?137999-LCD-touchscreen-A-development-thread
See, this is what I'm worried about myself. That's why I'm going to try it after the expo. I'm stuck with thru-hole components for now. Adapters are not out of the question, but if that's the case I may just go completely SMD and have an excuse to upgrade my tools.
Comments
I got most of the components from futurlec, but they can take a couple of weeks to arrive and sometimes it is hard to find parts on their website that you know they sell.
I found a mistake on the board. I'm using P16 for the clock and I need to use P19 or higher. I didn't read the spec sheet closely enough
So some tracks are going to need to be cut and moved. I think it will be a matter of driving all the clocks from P19 instead of P16, and then driving the memory /RD from P16 instead of P19. I'll need to think about where to put the changes on the board.
addit - found a few more things on the board that are not quite right. Apart from swapping things above, I think the schematic is right though. Hmm - I might have to hold off posting any boards though. Maybe better to build this on a breadboard first?
I did decide to order regulators and all necessary components.
I think it might be a good idea to breadboard first. I always start here if possible. Cutting a few traces is not a huge deal to me, but I will leave this up to you. I've been working on the old ili driver and almost done with ram to hub and hub to ram transfers. I need to get a jump start on homework for next week, but after this is done I will continue working.
*edit*
Okay, I've been working on the driver and hit an issue. I'm looking at the datasheet for my hc counters and see max clock 25MHZ @ 4.5V, 5MHZ @ 2v. *I'm going to slow it down for the LS, but will be going full HC - 3.3V compatible* So. How should I guestimate the timing cycle? Any advice? Just start slow and speed it up till it won't run?
another edit
I've been working on the ram read and write in ASM. None of this is tested, but I'm trying to get a framework. I think this should be close.
DAT ' First part tests ok '' +--------------------------------------------------------------------------+ '' | Dracblade Ram Driver (with grateful acknowlegements to Cluso) | '' +--------------------------------------------------------------------------+ org 0 tbp2_start ' setup the pointers to the hub command interface (saves execution time later ' +-- These instructions are overwritten as variables after start comptr mov comptr, par ' -| hub pointer to command hubptr mov hubptr, par ' | hub pointer to hub address ramptr add hubptr, #4 ' | hub pointer to ram address lenptr mov ramptr, par ' | hub pointer to length errptr add ramptr, #8 ' | hub pointer to error status cmd mov lenptr, par ' | command I/R/W/G/P/Q hubaddr add lenptr, #12 ' | hub address ramaddr mov errptr, par ' | ram address len add errptr, #16 ' | length err nop ' -+ error status returned (=0=false=good) ' Initialise hardware tristates everything and read/write set the pins init mov err, #0 ' reset err=false=good mov dira,zero ' tristate the pins done wrlong err, errptr ' status =0=false=good, else error x wrlong zero, comptr ' command =0 (done) ' wait for a command (pause short time to reduce power) pause ' mov ctr, delay wz ' if =0 no pause ' if_nz add ctr, cnt ' if_nz waitcnt ctr, #0 ' wait for a short time (reduces power) rdlong cmd, comptr wz ' command ? if_z jmp #pause ' not yet 'decode command ' cmp cmd, #"Z" wz ' Z moves command to the display from hub address, length times if_z jmp #hubtodisplayCommand ' command format "DoCmd(Z,hub_address, unused, length) cmp cmd, #"Y" wz ' Y moves data to the display from hub address, length times if_z jmp #hubtodisplayData ' data format "DoCmd(Y, hub_address, unused, length) cmp cmd, #"R" wz ' R = read block from external ram to hub if_z jmp #rdblock cmp cmd, #"W" wz ' W = write block from hub to external ram if_z jmp #wrblock cmp cmd, #"C" wz ' C moves a block of data from ram to the display if_z jmp #extramtodisplay ' add new commands HERE ' cmp cmd, #"A" wz ' A moves 256 bytes from hub to external ram ' if_z jmp #blockhubtoram ' cmp cmd, #"B" wz ' B moves 256 bytes from external ram to hub ' if_z jmp #blockramtohub ' cmp cmd, #"E" wz ' convert 3 byte .raw format to 2 byte .ili format - hub to hub ' if_z jmp #rawtoiliformat ' cmp cmd, #"F" wz ' draw a transparent icon, pass two locations in hub ram and len = number of pixels ' if_z jmp #drawicon cmp cmd, #"I" wz ' init if_z jmp #init ' mov err, cmd ' error = cmd (unknown command) jmp #done ram_open rdlong hubaddr, hubptr ' get hub address rdlong ramaddr, ramptr ' get ram address rdlong len, lenptr ' get length mov err, #5 ' err=5 ram_open_ret ret hubtodisplayData ' send a block of data blocklen from hubaddr to the display (bypasses external ram) call #ram_open ' gets hubaddr and len (ignores ramaddress) call #setRShigh ' set pins for data output :hubdisploop rdword Display, hubaddr ' copy word from hub, not needed ? add hubaddr,#2 ' add 2 to hub address changed for word alligned call #ilidisplayword ' send these bytes to the display djnz len,#:hubdisploop ' loop until done jmp #init ' set pins to tristate hubtodisplayCommand call #ram_open ' gets hubaddr and len (ignores ramaddress) :hubdisplayloop call #setRSlow ' set pins for Command output rdword Display, hubaddr ' copy word from hub add hubaddr,#2 ' add 2 to hub address changed for word alligned call #ilidisplayword ' send these bytes to the display djnz len,#:data ' loop until done jmp #init ' set pins to tristate :data call #setRShigh rdword Display, hubaddr ' copy word from hub add hubaddr,#2 ' add 2 to hub address changed for word alligned call #ilidisplayword ' send these bytes to the display djnz len,#:hubdisplayloop ' loop until done jmp #init ' set pins to tristate setRShigh mov outa, PinsInit mov dira, DirsEnabled ' set rsHigh by tristate pin setRShigh_ret ret setRSlow mov outa, PinsInit mov dira, DirsEnabled wz ' set rsHigh by tristate pin muxnz dira, RSpin ' set rsLow by enabling pin setRslow_ret ret ilidisplayword ' pass data out, sends out to the display add Display, p2dpins wz 'this add presets the data for control pins and primes WZ flag for mux operation mov outa, Display 'then make pins = data muxz dira,EnablePin 'make enable pin low mov timeout, #$f 'set wait period :wait1 djnz timeout, :wait1 'and wait muxnz dira, EnablePin 'make enable pin high ilidisplayword_ret ret '*********************************************************************************************************************************** 'tests ok '--------------------------------------------------------------------------------------------------------- 'Memory Access Functions rdblock call #ram_open ' get variables from hub variables call #load_ram_add ' load first address into counters rdloop call #read_memory_word ' read word from address into data_8 wrword data_8,hubaddr ' write data_8 to hubaddr ie copy WORD to hub add hubaddr,#1 ' add 1 to hub address add ramaddr,#1 ' add 1 to ram address call #inc_ram_address ' increment RAM address djnz len,#rdloop ' loop until done jmp #init ' reinitialise ' write block from hub to external ram wrblock call #ram_open call #load_ram_add ' load first address into counters mov dira, P2RPins wrloop rdword data_8, hubaddr ' copy word from hub call #write_memory_word ' write word from data_8 to address add hubaddr,#1 ' add 1 to hub address add ramaddr,#1 ' add 1 to ram address call #inc_ram_address ' increment RAM address djnz len,#wrloop ' loop until done jmp #init ' reinitialise load_ram_add mov outa, RamLoadPins wz 'preset pins and clear z flag. pins still tri-state add outa, ramaddr 'move rammaddress onto bus mov dira, RamLoadDirs 'and enable all pins 'wait here if needed? muxz outa, EnablePin ' make Enable Pin Low 'wait here if needed? muxnz outa, EnablePin ' make Enable Pin High 'wait? mov dira, zero ' tri-state all pins 'wait here if needed? load_ram_add_ret ret read_memory_word mov outa, R2PPins ' preset pins for read mov dira, R2PDirs ' enable pins add timeout, RAMRDtimeout 'wait here if needed :wait djnz timeout, #:wait mov data_8, ina and data_8, #$FF ' extract 16 bits read_memory_word_ret ret write_memory_word and data_8, lowWordMask ' ensure upper bytes=0 add data_8, P2RPins ' add to P2E initPins mov outa, data_8 wz ' send it out muxz outa, Cadd1Pin ' make 138 = RAMWR muxz outa, EnablePin ' make ram WR LOW add timeout, RAMWRtimeout 'set wait :wait djnz timeout, #:wait 'and wait muxnz outa, EnablePin ' make ram WR HIGH muxz outa, Cadd1Pin ' make 138 = COUNT write_memory_word_ret ret inc_ram_address add zero, #0 wz 'prime z flag muxnz outa, EnablePin 'make Enable Pin LOW mov timeout, countTimeout 'set wait :wait djnz timeout, #:wait 'and wait muxz outa, EnablePin 'make enable Pin High 'and wait again? ' mov timeout, countTimeout 'set wait ':wait djnz timeout, #:wait 'and wait inc_ram_address_ret ret 'extramtodisplay ' send a block of data blocklen from external memory ramaddress to the ILI9325 display call #ram_open ' gets ramaddr and len (ignore hubaddr) call #load_ram_add ' loads ram address for transfer mov outa, R2DPins ' preset pins for R2D transfer mov dira, R2DDirs ' enable pins 'and wait if necessary? add zero, #0 'prime z flag ililoop muxnz outa, EnablePin ' make enable pin LOW mov timeout, #$f ' set wait :wait1 djnz timeout, #:wait1 ' and wait muxz outa, EnablePin 'make enable pin HIGH muxnz outa, Cadd0Pin ' set for ramcount call #inc_ram_address ' and load next ram address muxz outa, Cadd0Pin ' set for lcd_wr mov timeout, #$f ' set wait :wait2 djnz timeout, #:wait2 ' and wait djnz len,#ililoop ' loop until done jmp #init ' set pins to tristate RAMRDtimeout long $0000_00FF RAMWRtimeout long $0000_00FF countTimeout long $0000_00FF lowWordMask long $0000_ffff 'pin settings EnablePin long %00000000_00000010_00000000_00000000 RSPin long %00000000_00000001_00000000_00000000 LoadPin long %00000010_00000000_00000000_00000000 RamLoadPins long %00001100_01000010_00000000_00000000 RamLoadDirs long %00001111_11100010_11111111_11111111 R2PDirs long %00001101_11100010_00000000_00000000 P2RDirs long %00001001_11100010_00000000_00000000 P2RPins long %00001110_01000010_00000000_00000000 R2PPins long %00000010_01000010_00000000_00000000 R2DPins long %00000000_01100011_00000000_00000000 R2DDirs long %00000101_11100011_00000000_00000000 p2dpins long %00001000_01100000_00000000_00000000 ' propToDisplay enable pin low, but tristate, primed for lcd transfer PinsInit long %00001001_01100010_00000000_00000000 'pins Inital state, BUS = Prop -> RAM, Not RamRD, BusDisabled, enable pin high DirsEnabled long %00001001_11100000_11111111_11111111 '' (R4Fh) (POR = 0000h) CAdd0Pin long %00000000_00100000_00000000_00000000 Cadd1Pin long %00000000_01000000_00000000_00000000 Cadd2Pin long %00000000_10000000_00000000_00000000 timeout res 1 Display res 1 fit
I will keep updating this until it works, I just wanted to get a start so you could make suggestions. Also, here's the schematicI did not want to use the inverters, but couldn't think of an easier way. Let me know what you think!
*edited*
I found more issues. I forgot to remove a few resistors from the lcd lines. I am also thinking about adding a 4 pin jumper for midi I/O or PS2 port.
I got routines working tonight to transfer data from hub to ram and ram to hub
PUB HubToRam(RamAddress,Number) | i ' send data from hub to ram in a block Load161(RamAddress) ' load all the 161 chips with the start value i := 0 repeat Number OUTA &= %11111111_11111111_00000000_00000000 ' clear for output OUTA |= rambuffer[i] ' send out a word to P0-P15 WR_Low ' write to ram WR_High ' toggle ram write Clock161_Low ' toggle clock Clock161_High i += 1 ' increment i PUB RamToHub(RamAddress, Number) | i ' send data from ram to hub in a block Load161(RamAddress) ' load all the 161 chips with the start value i := 0 DIRA &= %00001111_11111111_00000000_00000000 ' set P0-P15 as inputs repeat Number RD_Low ' read pin low rambuffer[i] := INA ' get the data RD_High Clock161_Low ' toggle clock Clock161_High i += 1 ' increment i DIRA |= %00000000_00000000_11111111_11111111 ' restore P0-P15 as outputs
So - move data from SD card to propeller, prop to external ram, external ram back to prop, and external ram to the display. This last one is where the fast refresh works with 30ms to do a screen. It is super simple in spin and so will easily translate over to pasm
PUB RamToDisplay(RamAddress,Number) ' send n words to the display after sending a Draw command Load161(RamAddress) ' load all the 161 chips with the start value ILI_RS_High ' RS high for sending data RD_Low ' memory read low DIRA &= %00001111_11111111_00000000_00000000 ' set P0-P15 as inputs so no data clash with propeller (prop ignores these pins) repeat Number ILI_WR_Low ' send out the data ILI_WR_High Clock161_Low ' toggle clock Clock161_High RD_High ' memory read high DIRA |= %00000000_00000000_11111111_11111111 ' restore P0-P15 as outputs
This little bit of code fills the screen from the ram with 76800 pixels (15% of the ram capacity)
Draw(0,0,239,319) ' dump out 76800 words to the display = a full screen RamToDisplay(0,76800)
and the speed in spin is 5.5 seconds, which I think compares favorably with the previous speed around 9 seconds. This is going to be very fast in pasm.
This 161 driver is brilliant!
Full program:
'' ILI9325 driver using the Touchblade161 design for faster ram to display transfers '' James Moxham 2012 CON _clkmode = xtal1 + pll16x ' use crystal x 16 _xinfreq = 5_000_000 _1ms = 1_000_000 / 1_000 ' Divisor for 1 ms ' pins ' P24 = audio out ' 25,26,27 138 one of 8 decoded, active low ' 0=000 = SPI touchscreen input, keyboard, TV VGA enabled ' 1=001 = Load counter ' 2=010 = Memory transfer - P0-P15=bus, P19=161_clk, P17 = ILI_WR, P18=ILI_RS, P16= Ram_RD, P20=Ram_WR,P21-23 = SD card ' 3=011 = ILI Reset ' 4=100 = Digital output (8 bits to a 574 latch) ' 5=101 = spare ' 6=110 = spare ' 7=111 = startup (all above deselected) OBJ VAR long orientation long curx, cury long clkcycles ' for the delay routine PUB Main curx :=0 cury :=0 PinsHigh start_ram ' start the cog driver MemoryTransferSelect ' select 138 and set control pins Start_ILI9325 ' start the display HelloWorld ' Bootup message rambuffer[0] :=$AA55 ' some random word values rambuffer[1] :=$07FF rambuffer[2] := %00000111_11100000 ' green pixels rambuffer[3] := %00000111_11100000 rambuffer[4] := %11111000_00000000 ' red pixels rambuffer[5] := %11111000_00000000 rambuffer[6] := %11111000_00000000 HubToRam(0,7) ' ramaddress, number. Uses rambuffer (word array) up to 256 rambuffer[1] := 0 ' clear the value for debugging RamToHub(0,7) ' read data back MemoryTransferSelect ' reselect 138 for display output for debugging hex(rambuffer[1],4) Draw(99,95,108,104) ' draw a little black square repeat 100 Pixel(0) Draw(100,100,106,100) ' display pixels RamToDisplay(0,7) ' dump out from ram to display repeat PUB RamToDisplay(RamAddress,Number) ' send n words to the display after sending a Draw command Load161(RamAddress) ' load all the 161 chips with the start value ILI_RS_High ' RS high for sending data RD_Low ' memory read low DIRA &= %00001111_11111111_00000000_00000000 ' set P0-P15 as inputs so no data clash with propeller (prop ignores these pins) repeat Number ILI_WR_Low ' send out the data ILI_WR_High Clock161_Low ' toggle clock Clock161_High RD_High ' memory read high DIRA |= %00000000_00000000_11111111_11111111 ' restore P0-P15 as outputs PUB HubToRam(RamAddress,Number) | i ' send data from hub to ram in a block Load161(RamAddress) ' load all the 161 chips with the start value i := 0 repeat Number OUTA &= %11111111_11111111_00000000_00000000 ' clear for output OUTA |= rambuffer[i] ' send out a word to P0-P15 WR_Low ' write to ram WR_High ' toggle ram write Clock161_Low ' toggle clock Clock161_High i += 1 ' increment i PUB RamToHub(RamAddress, Number) | i ' send data from ram to hub in a block Load161(RamAddress) ' load all the 161 chips with the start value i := 0 DIRA &= %00001111_11111111_00000000_00000000 ' set P0-P15 as inputs repeat Number RD_Low ' read pin low rambuffer[i] := INA ' get the data RD_High Clock161_Low ' toggle clock Clock161_High i += 1 ' increment i DIRA |= %00000000_00000000_11111111_11111111 ' restore P0-P15 as outputs PUB Load161(RamAddress) Select138(7) ' deselect previous 138 value DIRA |= %00000000_00011111_11111111_11111111 ' P0-P18 enabled for output plus P19,P20 OUTA &= %00001110_11111000_00000000_00000000 ' preserve previous values but set A0-18 low OUTA |= RamAddress ' output address to the 161 chips Clock161_Low ' clock low Select138(1) ' 161 load low Clock161_High ' load in value OUTA |= %00000000_11111111_00000000_00000000 ' set P16-P23 high prior to changing 138 Select138(2) ' 161 load high and back to mem transfer PUB Clock161_Low OUTA &= %11111111_11110111_11111111_11111111 ' P19 low PUB Clock161_High OUTA |= %00000000_00001000_00000000_00000000 ' P19 high PUB WR_Low OUTA &= %11111111_11101111_11111111_11111111 ' P20 low PUB WR_High OUTA |= %00000000_00010000_00000000_00000000 ' P20 high PUB RD_Low OUTA &= %11111111_11111110_11111111_11111111 ' P16 low PUB RD_High OUTA |= %00000000_00000001_00000000_00000000 ' P16 high PUB PinsHigh DIRA := %00001111_11111111_11111111_11111111 ' enable all pins as outputs OUTA := %00001110_11111111_11111111_11111111 ' all except P24 audio out are high PUB MemoryTransferSelect Select138(2) ' enable memory transfer group DIRA |= %00001110_11111111_11111111_11111111 ' Pins all as outputs OUTA |= %00000000_11111111_00000000_00000000 ' all control pins high PUB Select138(n) ' pass n=0 to 7 n := n<<25 ' shift left so pins 25,26,27 DIRA |= %00001110_00000000_00000000_00000000 ' enable these pins for output OUTA &= %11110001_11111111_11111111_11111111 ' mask 3 pins low OUTA |= n ' send out PUB Clearscreen Draw(0,0,239,319) ' clear the screen - slow spin version repeat 76800 Pixel($0000) PUB HelloWorld ' use propeller font in the rom for bootup messages when debugging sd cards Propfont_string(string("Hello World")) ' string to send PUB Propfont_string(stringptr) 'print at curx,cury repeat strsize(stringptr) Propfont_out(byte[stringptr++]) crlf PUB crlf curx := 0 cury += 32 ' new line at end of string if cury >319 ' bottom of screen so new screen curx:=0 cury:=0 PUB Propfont_out(ascii) | address,pixels Draw(curx,cury,curx+15,cury+31) ' location to start drawing address := $8000 + (ascii >> 1) << 7 ' get rom address repeat 32 ' 32 rows per character, split in two parts pixels := long[address] ' get rom font data pixels := pixels >> (ascii & 1) ' shift for odd characters repeat 16 ' 16 columns if pixels & 1 Pixel(%00000111_11100000) ' foreground color RRRRRGGG_GGGBBBBB else Pixel(%00000000_00000000) ' background color pixels := pixels >> 2 ' alternate pixels interleaved so shift 2 address += 4 curx +=16 if curx >239 ' new line crlf PUB Start_ILI9325 ' pass orientation true = portrait, false = landscape ILI_Reset_High pause1ms(5) ILI_Reset_Low pause1ms(5) ILI_Reset_High ILI_CS_High ILI_RD_High ILI_WR_High pause1ms(5) ILI_CS_Low ' ************* Start Initial Sequence ********** ILIcmd($00E5,$78F0) ' set SRAM internal timing ILIcmd($0001,$0100) ' set SS and SM bit 0001 0100 portrait ILIcmd($0002,$0700) ' set 1 line inversion ILIcmd($0003,$1030) ' set GRAM write direction and BGR=1. $0003 $1030 ILIcmd($0004,$0000) ' Resize register ILIcmd($0008,$0207) ' set the back porch and front porch ILIcmd($0009,$0000) ' set non-display area refresh cycle ISC[3:0] ILIcmd($000A,$0000) ' FMARK function ILIcmd($000C,$0000) ' RGB interface setting ILIcmd($000D,$0000) ' Frame marker Position ILIcmd($000F,$0000) ' RGB interface polarity ' *************Power On sequence ****************// ILIcmd($0010,$0000) ' SAP, BT[3:0], AP, DSTB, SLP, STB ILIcmd($0011,$0007) ' DC1[2:0], DC0[2:0], VC[2:0] ILIcmd($0012,$0000) ' VREG1OUT voltage ILIcmd($0013,$0000) ' VDV[4:0] for VCOM amplitude ILIcmd($0007,$0001) pause1ms(50) ' Dis-charge capacitor power voltage ILIcmd($0010,$1090) ' 1490//SAP, BT[3:0], AP, DSTB, SLP, STB ILIcmd($0011,$0227) ' DC1[2:0], DC0[2:0], VC[2:0] pause1ms(50) ' delay ILIcmd($0012,$001F) ' 001C// Internal reference voltage= Vci; pause1ms(50) ' delay ILIcmd($0013,$1500) ' $1000//1400 Set VDV[4:0] for VCOM amplitude 1A00 ILIcmd($0029,$0027) ' $0012 //001a Set VCM[5:0] for VCOMH //$0025 0034 ILIcmd($002B,$000D) ' Set Frame Rate 000C pause1ms(50) ' delay ILIcmd($0020,$0000) ' GRAM horizontal Address ILIcmd($0021,$0000) ' GRAM Vertical Address ' ----------- Adjust the Gamma Curve ----------// ILIcmd($0030,$0000) ILIcmd($0031,$0707) ILIcmd($0032,$0307) ILIcmd($0035,$0200) ILIcmd($0036,$0008) ILIcmd($0037,$0004) ILIcmd($0038,$0000) ILIcmd($0039,$0707) ILIcmd($003C,$0002) ILIcmd($003D,$1D04) ' ------------------ Set GRAM area ---------------// ILIcmd($0050,$0000) ' Horizontal GRAM Start Address ILIcmd($0051,$00EF) ' Horizontal GRAM End Address ILIcmd($0052,$0000) ' Vertical GRAM Start Address ILIcmd($0053,$013F) ' Vertical GRAM Start Address ILIcmd($0060,$A700) ' Gate Scan Line ILIcmd($0061,$0001) ' NDL,VLE, REV ILIcmd($006A,$0000) ' set scrolling line ' -------------- Partial Display Control ---------/ ILIcmd($0080,$0000) ILIcmd($0081,$0000) ILIcmd($0082,$0000) ILIcmd($0083,$0000) ILIcmd($0084,$0000) ILIcmd($0085,$0000) ' //-------------- Panel Control -------------------// ILIcmd($0090,$0010) ILIcmd($0092,$0600) ILIcmd($0007,$0133) ' 262K color and display ON ChangeOrientation(true) ' default to portrait PUB ChangeOrientation(n) ' pass true = portrait or false = landscape, changes global variable orientation in this object orientation := n if orientation ILIcmd($0001,$0100) ' set SS and SM bit 0001 0100 portrait ILIcmd($0003,$1030) ' set GRAM write direction and BGR=1. $0003 $1030 else ILIcmd($0001,$0000) ' set SS and SM bit 0001 0000 landscape ILIcmd($0003,$1038) ' landscape $1028 = original but 1038 is correct - not mirror image PUB Draw(x1, y1, x2, y2) ' sets the pixel to x1,y1 and then fills the next (x2-x1)*(y2-y1) pixels ifnot orientation ' landscape mode so swap x and y result :=x1 ' swap x1 and y1 x1 := y1 y1 := result result := x2 ' swap x2 and y2 x2 :=y2 y2 := result ILIcmd($0050,x1) ILIcmd($0052,y1) ILIcmd($0051,x2) ILIcmd($0053,y2) ILIcmd($0020,x1) ILIcmd($0021,y1) Lcd_Write_Com($0022) PUB Pixel(pixelcolor) ' send out a pixel Lcd_Write_Data(pixelcolor) PUB pause1ms(period) '' Pause execution for period (in units of 1 ms). clkcycles := ((clkfreq / _1ms * period) - 4296) #> 381 ' Calculate 1 ms time unit waitcnt(clkcycles + cnt) ' Wait for designated time PUB hex(value, digits) '' Print a hexadecimal number propfont_out("O") propfont_out("x") value <<= (8 - digits) << 2 repeat digits propfont_out(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) crlf PRI ILIcmd(c,d) ' instruction in one method Lcd_Write_Com(c) ' send out a word Lcd_Write_Data(d) PRI Lcd_Write_Com(ILIlong) ILI_RS_low LCD_Writ_Bus(ILIlong) PRI Lcd_Write_Data(ILIlong) ILI_RS_High LCD_Writ_Bus(ILIlong) PRI LCD_Writ_Bus(ILILong) 'ILILong &= %00000000_00000000_11111111_11111111 ' mask to a word. Not needed if care taken always to send a word value OUTA &= %11111111_11111111_00000000_00000000 ' set P0-P15 to zero ready to OR OUTA |= ILILong ' merge with the word to output ILI_WR_Low ' send out the data ILI_WR_High PRI ILI_RS_Low OUTA &= %11111111_11111011_11111111_11111111 ' P18 low PRI ILI_RS_High OUTA |= %00000000_00000100_00000000_00000000 ' P18 high PRI ILI_RD_Low ' pulled high in hardware, not used PRI ILI_RD_High PRI ILI_WR_Low OUTA &= %11111111_11111101_11111111_11111111 ' p17 low PRI ILI_WR_High OUTA |= %00000000_00000010_00000000_00000000 ' p17 high PRI ILI_CS_Low ' not used as setting 138 to %010 does this PRI ILI_CS_High PRI ILI_RESET_Low ' reset low Select138(3) ' reset low PRI ILI_RESET_High Select138(2) ' 138 back to memselect DAT sdbuffer byte $0[512] ' 512 byte buffer for sd card interface rambuffer word $0[256] '************************** Cog driver for the 16 bit ILI9325 screen ********************* VAR ' communication params(5) between cog driver code - only "command" and "errx" are modified by the driver long command, hubaddrs, ramaddrs, blocklen, errx, cog ' rendezvous between spin and assembly (can be used cog to cog) ' command = R, W, H I,D etc =0 when operation completed by cog ' hubaddrs = hub address for data buffer ' ramaddrs = ram address for data ($0000 to $FFFF) ' blocklen = ram buffer length for data transfer ' errx = returns =0 (false=good), else <>0 (true & error code) ' cog = cog no of driver (set by spin start routine) PUB start_ram : err_ ' Initialise the Drac Ram driver. No actual changes to ram as the read/write routines handle this command := "I" cog := 1 + cognew(@tbp2_start, @command) if cog == 0 err_ := $FF ' error = no cog else repeat while command ' driver cog sets =0 when done err_ := errx ' driver cog sets =0 if no error, else xx = error code PUB stop_ram if cog cogstop(cog~ - 1) PUB DoCmd(command_, hub_address, ram_address, block_length) : err_ ' Do the command: R, W, N, F, H,I,D hubaddrs := hub_address ' hub address start ramaddrs := ram_address ' ram address start blocklen := block_length ' block length command := command_ ' must be last !! ' Wait for command to complete and get status repeat while command ' driver cog sets =0 when done err_ := errx ' driver cog sets =0 if no error, else xx = error code DAT '' +--------------------------------------------------------------------------+ '' | Dracblade Ram Driver (with grateful acknowlegements to Cluso) | '' +--------------------------------------------------------------------------+ org 0 tbp2_start ' setup the pointers to the hub command interface (saves execution time later ' +-- These instructions are overwritten as variables after start comptr mov comptr, par ' -| hub pointer to command hubptr mov hubptr, par ' | hub pointer to hub address ramptr add hubptr, #4 ' | hub pointer to ram address lenptr mov ramptr, par ' | hub pointer to length errptr add ramptr, #8 ' | hub pointer to error status cmd mov lenptr, par ' | command I/R/W/G/P/Q hubaddr add lenptr, #12 ' | hub address ramaddr mov errptr, par ' | ram address len add errptr, #16 ' | length err nop ' -+ error status returned (=0=false=good) ' Initialise hardware tristates everything and read/write set the pins init mov err, #0 ' reset err=false=good mov dira,zero ' tristate the pins done wrlong err, errptr ' status =0=false=good, else error x wrlong zero, comptr ' command =0 (done) pause rdlong cmd, comptr wz ' command ? if_z jmp #pause ' not yet ' decode command cmp cmd,#"M" wz ' move a block from ram to the display if_z jmp #moveblock cmp cmd, #"I" wz ' init if_z jmp #init mov err, cmd ' error = cmd (unknown command) jmp #done '--------------------------------------------------------------------------------------------------------- ram_open rdlong hubaddr, hubptr ' get hub address rdlong ramaddr, ramptr ' get ram address rdlong len, lenptr ' get length mov err, #5 ' err=5 ram_open_ret ret Moveblock ' uses ramaddr and len ' OUTA := address ' address is not latched - this is where the speed is ' OUTA &= %11111111_10111111_11111111_11111111 ' ILI write low ' OUTA |= %00000000_01000000_00000000_00000000 ' ILI write high ' address++ ' increment address mov dira,direction ' set P0-P23 as outputs call #ram_open ' get ramaddr and len or ramaddr,pin22 ' start with pin 22 high Moveblock_loop mov outa,ramaddr ' send out the address value andn outa,pin22 ' set pin 22 low or outa,pin22 ' set pin 22 high add ramaddr,#1 ' increment ram address djnz len,#moveblock_loop jmp #init halt jmp #halt ' ************************ Variables ****************************** delay long 80 ' waitcnt delay to reduce power (#80 = 1uS approx) Zero long %00000000_00000000_00000000_00000000 ' for tristating all pins pin22 long %00000000_01000000_00000000_00000000 direction long %00000000_11111111_11111111_11111111 fit 496
Here's the schematics, and a basic idea for a layout. I am unable to layout a board because I am using eagle light. If you would do me a HUGE favor and throw a layout together, I will send you one when they're printed.
Re getting boards made I wonder if 3.3V memory chips would be better as there would be an extra cost with the board space required for the resistors?
Concerning switching to 3.3v, I guess it's really a trade-off between speed and board footprint. I'm not sure how much space those resistors would add, nor how much more it would cost. I am also unsure what difference running @5v will do to clock speed. The 161's are rated @ 4.5 and 2 volts supply. Max frequency @2v is 6mhz, at 4.5v it's 30mhz. I'm wondering if this will help speed transfers from hub to ram and ram to hub. This will not improve ram to display writes, but should double working frequency? I would be interested to see what the max you're clocking your boards at. If it's close to the 30mhz side then I would say the switch to 3.3v would be ok. If it's under half I think the 5v would be best.
If we can get the cost of a 3.3-5v board under $20 bucks, then it would be worth a short run to me.
*edit*
JP2 could be removed, and ext_out replaced with a single pin or this pin could be added to FPouts. This would save a bit of board space.
Yes, sorry about that - not able to extract things from the work computer. I'll take a look when I get home.
Thanks for the hints re the clock freq. Hopefully over the next few days I'll get a chance to push it all to pasm speeds. Start with some NOPs and then remove them one by one. The loop to move data from ram to display is only 4 pasm instructions plus one DJNZ so we shall see how fast it can go. I suspect the propogation of the overflow through the five 161 chips might be a limiting factor. Shouldn't matter though - 30ms vs 60ms for a screen refresh would not be noticable.
I'd still hold re getting boards made. Still a few things to test out. My working board is becoming a mess of wire wrap links and drilled out vias but it is helping refine what the final working board is going to look like. I know with what we have that this is going to be quick. I think we can get it to 'ipad' speeds - touch the display and something happens instantly. Compared with my android pandapad, I can say we have already moved beyond 'android speed' for some things. (especially bootup time). All very exciting.
I apologize for being antsy to print boards, but I do not have enough room on the breadboards I have to put this together. Don't want to buy ANOTHER board, but just might. I'm ordering parts REAL soon, having larger ram will be nice.
I totally agree that we are moving beyond android speeds. I switched back to my DUMB OLD hardware to work on Midi implementation, as well as put the finishing touches on my guitar switcher. I added mono audio out and midi i/o. Have not tested either because I'm trying to get the screen working again. I don't know what I did, but I messed something up.
So I was just looking over the datasheet for the 161's again. Found a neat little formula for cascaded counting.
1/ (CP to TC prop. delay + TE to CP setup +TE to CP hold) = about max frequency
So for my figuring from the datasheet, for 2v operation.
1 / (185 + 50 + 0) = about 4MHZ
This is a long way from 21MHZ spec'd @ 4.5V. I know we're not running @2v, but 3.3. Not sure how this scales across, but it will be interesting to see your results. Now back to making new code work on old hardware. *headache*
*edited*
I just flashed on an idea to save some board space for the PropERMidi board. Move the resistors for the lcd screen to a board that stands between the two. Not the most elegant solution, but a solution nonetheless.
Re designs, I am working tonight on the SD driver and looking at the code out there, eg Kye's driver, it really does make things a lot simpler to devote 4 dedicated prop pins to the SD card. I had devoted P21-P23 with the /CS line decoded elsewhere but it will mean customising Kye's driver and I'd rather keep it as the standard version.
So I'm going to steal P24 which is the audio output for /CS and then for audio, borrow P29 which is the eeprom data line.
Schematic attached.
I've got some spare breadboards - I'll post them to you tomorrow.
Also for audio, I might use some lower number pins rather than P29, and then use two pins and get stereo. Kye's original SD driver contained a wav player and it would be cool to have a music player as one of the touchscreen icons.
In a general sense, once all the prop pins have been used to move pictures around from SD card to ram to the screen, that part can go to sleep and there are now a lot of free propeller pins for MIDI and other i/o.
I'm not sure about left shifting. It isn't just the speed, it is also whether there are enough pins. The way I am doing things, once a picture has been sent to the screen, P0-P20 are free. In practice that would mean that if you want to play a song, you can't update the screen at the same time. But you can be polling for the screen being touched. There is a potential solution though - instead of decoding P25-P27 through a 138, use a MCP23008 on the I2C bus.
Midi is a bit like RS232, right? In which case, outputs can be pins that you can enable when you need them. Inputs on the other hand need dedicated pins.
So maybe we can free up P25-P27, use two for audio, one for Midi IN, and then intermittently enable another prop pin for midi OUT (ie you can only output if the screen is not being updated).
Midi is quite a lot like 232. 7-bit asynchronous-serial, inverted, at 31.25k? I can't remember the number exactly. The spec also uses opto-isolators to combat ground loops. Not too big of a deal. The only reason my design requires CONSTANT midi in AND OUT is because I plan on doing Midi Time Code to Midi Clock conversion and vice versa. Not a feature I will be using all the time, but it will come in VERY handy when I do need it .
Hit the reset button, it boots into a simple text display running from the propeller ROM to display "SD". If the SD card works, it loads a font and displays a message. And then it reads a picture off the SD card and displays it.
Unzip the file and put the .ili picture and the .ifn font file on the SD card.
There was a fair bit of recoding - everything changed from big-endian to little-endian. Lots of pasm code to rewrite.
But the 161 concept is sound - it is (surprisingly) faster to have 5 external counter chips than it is to use the propeller's internal counters.
The code to update the display from ram did not need any NOPs or delays. It is just 5 pasm instructions to send two bytes.
ramtodisplay_loop andn outa,maskP17 ' ILI write low or outa,maskP17 ' ILI write high andn outa,maskP19 ' clock 161 low or outa,maskP19 ' clock 161 high djnz len,#ramtodisplay_loop
76800 words = 153600 bytes, transferred in 30ms = 5.12 megabytes per second = 40.96 megabits per second.
Keep up the great work!
I think you started off with a spin version that took 9 seconds to refresh the screen. So we are just under 300x faster than that. I've very pleased that there were no problems with the overflow delays through the 161 chips. Your circuit is so simple but so clever!
One nice thing about these fast screen refreshes - you can get on with other things like making music without having to worry about the screen so much.
I need to think about icons. The previous code used .raw files with RGBA where A is a transparency layer. I takes longer to process on the fly. I am thinking that when you load an icon, take the background where it is going to go and store that in a file and combine it with the icon file so that when you re-display that icon it draws the background at the same time. So icon files are two bytes per pixel not four, and there is a separate transparency file. It means you can't move icons so easily, but generally they stay in the same place anyway. Should speed up icon refreshes about 100x so I think it is worth it.
Transparency is very nice, I've had some issues because I have not programmed anything for that. I don't see moving icons as too big of a deal. As long as we can define a decent sized character and move that easily *remember the old faders? gotta finish that eventually!*
G2G, Thank you SO SO SO much!
Joe
*edit*
I've been thinking about a screen designer. There are many ways to go, but my initial efforts playing with the fader idea were slow and laborious. A bank of custom, system characters will be needed. This includes transport controls such as play, pause, stop, FF, and RW. I HAD example layouts in PF, but lost these due to stupidity. They were very slow to draw since they used multiple characters. This will work WAY better and be WAY faster
Also, you need a name for your current board. Eurocard_Touchscreen_161 is too long
PUB RawPicture | i' take a standard RGB .raw file and convert to two byte RRRRRGGGGGGBBBBB format and fill memory fat.openfile(string("synth.raw"),"R") ' a .raw file 240 wide, 320 high i := 0 repeat 600 fat.readdata(@sdbuffer,384) ' 240x320=76800 bytes x3 docmd("E",@sdbuffer,@rambuffer,128) ' convert to 2 byte HubToRam(i,128) ' send to external ram i += 128 ' increment external ram counter fat.closefile ' close file DisplayPicture ' display the picture
Photo of this displaying "synth.raw"
This is what we need for audio - but maybe sliders might be better than circular knobs? Easier to use with a touchscreen?
Is there a PCB available? If so I would like to have one for doing a software reference design for this type of hardware. I've been thinking about this 161 load and strobe idea a long time like used int NES cartridges, but have been too busy to act on it. It would be nice to use and support an existing hardware design before making my own.
Thanks,
--Steve
Ripple Carry Out "RCO" transitions low to high when Q outputs go from X to $F.
How can you guarantee that the next "nibble" counter is 0 while the first stage counter is $F?
That is: if you load $0000E to 5 counters and strobe the clock once, you want to get $0000F. Then strobe again to get $00010.
So the sequence you want is : load $0000E, strobe one gets $0000F, strobe two gets $00010.
This seems to happen instead: load $0000E, strobe one gets $0001F, strobe two gets $00010.
What really happens? Don't you need an inverter on the RCO for clocking the next stage?
Thanks,
--steve
The 74LV161 widely available in TSSOP and SO packages. That plus an extra $1 per SRAM beats analog uncertainty to me.