ervin@pinbot.enet.dec.com (Joseph James Ervin) (04/05/91)
Hello fellow HP48SX hackers, Here are my current findings on the display. Basically, the previous posting on this topic by Johan Thornton back in DEC-1990 was largely correct (as far as I can tell), but the descriptions of locations #128h and #129h appear to have been inaccurate, and I have added the definition of #130h-#134h. I have also added more information regarding the register at #100h, and some of the other registers. ******************************************************************** >Pressing ON-D, backspace, enter causes the memory scanner/editor to go to >address #00100h, which is where the HP48SX's display controller is. > > > > #00100h: bits 0-1 control the 4 pixel offset of the display. Useful for > smooth scrolling. Bit 2 is also involved here but messes up the > scan length. Bit 3 seems to put the machine into a coma. The "4 pixel offset of the display" is not a good description. Bits <2:0> of this location define the number of bits to ignore at the beginning of each horizontal scan line. Thus setting <2:0>=1 causes the whole display to shift 1 pixel to the left; <2:0>=2 causes the display to shift 2 pixels to the left, etc.. Thus, this is really an 8-pixel "scan-start offset", defining how many pixels to skip (from 0 to 7) at the beginning of each scan line. It's not quite that easy, however, so read on. Setting bit <2> when in memory scanner mode appears to "screw up" the display, making it unreadable (the rows of pixels no longer line up properly to form characters). I offer the following explanation. Setting bit <2:0>=100b, for example, tells the display controller to skip 4 pixels at the start of each line, which it does very nicely. The problem is that whenever bit <2> is set, the display controller also skips an additional byte at the END of each scan line. I'm not sure exactly _why_ this happens, but it does. In a graphic which can be scrolled, this is not a problem because the overscan register (#125h-#127h, below) can be decreased by one to compensate. This, however, is not possible when there are no "extra" bits in the memory pattern being skipped over. For example, imagine your image is wider than the screen. In that case, the overscan register (see below) is programmed to cause the display controller to skip over the bits on each row that exist to the right of the current row (and to the left of the next row) of the display. When scrolling to the right, then, the overscan register can just be decremented by one (when necessary) to make the horizontal scroll effect of register #100h work. Note, the scan-start offset register at #100h does not seem to effect the menu portion of the display (see below). > #00101h: LSBs of the 5 bit contrast control word. > #00102h: bit 0 is the MSB of the contrast. Bits 1 and 3 control the > voltage difference across the LCD; this is what you modified. > Can't see what bit 2 does. > #00103h: bit 3 is also involved in the LCD voltage control. > > #0010Bh: bit 0,1,2,3: \<-, \->, alpha, and alarm indicators > #0010Ch: bit 0,1: busy and I/O indicators; bit 3 must be set for the > indicators to be on. No arguments here. > #00120h - #00124h: display address base register. Ususally set to #F097Ch > (or #F09BC with the equation card installed) but you can change it, > to look at any memory you want. Note that you can't read this > register, just write to it. Remember to type addresses in > backwards. This should probably be renamed something like "stack display address pointer", since there is another display pointer at #130h-#134h used to map the menu portion of the screen. Note that bit <0> of both of these address pointers is ignored, so this is effectively a byte address. In other words, the display memory must start on a byte boundary. > #00125h - #00127: amount of overscan per pixel line The author of the original post neglected to say that this is measured in _bytes_, so <127,126,125> = 001 means skip 1 byte of memory after the end of each scan line before starting the next scan line. Note this is needed for storing image data that is wider than the screeen. I suspect that this is how the system handles the scrolling of graphics images wider than the display. When you scroll the plotting display, the system uses the above mentioned pixel scan-start offset (#100h) in conjuction with the overscan, and also modifies the address pointer at 120-124. > #00128h : offset to menu area bitmap, normally 7. > #00129h : bits 0-1 control the location of the menu area, normally 3. Don't > mess with bit 2, which can totally remap your calculator's display! > ON-C does not fix what happens, but turning it off does, strangely > enough. Locations #128 and #129 actually work together to provide a pointer to where the menu portion of the display starts; call it the "menu row index". Location #128<3:0> contains the lower four bits and #129<1:0> comprise the upper two bits. Recall that there are 64 rows of pixels on the screen. Note also that this field is 6 bits wide, and 2^6=64. This field thus provides the display controller with a pointer to the row on which the menu portion of the screen begins. Numbering the screen rows 0 through 63 from the top, the display controller causes the menu to start on the row pointed to by the menu row index register PLUS ONE. In other words, a menu row index of 0d causes the menu to start at the second row from the top (row #1d by the above numbering scheme), and a menu row index of 62d causes the menu to start at the very last row of the display (row #63d), yielding a 1 pixel high menu. Note that this 6-bit field normally contains 110111b=55d, which is the row where the menu normally resides (rows #56d-#63d). Notice how when viewing a plot, you can choose to have the menu area visible or use the whole screen for the plot? There's a way of telling the display controller to not display the menu by mapping it off the screen. In this case, the display controller fills the screen with data starting at the "stack address pointer", #120h-#124h. The menu can be mapped off the screen by setting the menu row index to 111111b=63d, which points to the "row" below the bottom row of the display. Because of interference from the memory scanner, it is difficult to determine whether writing a value of 0 to the menu row index actually maps the menu to row 2, or whether it turns the menu off altogether. Further experimentation from ML should reveal which is actually happening. So, the display controller actually has two sets of pointers for two areas on the screen. The first is the "stack address pointer" at #120h-#124h, and the second is a "menu address pointer" at #130h-#134h. Experimentation has shown that when they overlap, the menu data seems to win. It is my belief that on each screen refresh, the display controller takes the stack address pointer and drives that data onto the screen as directed by the overscan and pixel offset values. It seems that the display controller may keep track of how far down to write the stack image based on the contents of the menu row index registers (#128h-#129h). The display controller then apparently writes the menu portion of the screen, starting at the memory address pointed to by the menu address pointer register (#130h-#134h) and at the screen row pointed to by the contents of the menu row index register (#128h-#129h). The display controller writes through to the end of the screen. Thus, you can divide up the screen between the "stack" and "menu" portions in any proportions, with the apparent limitation that the menu must be below the top row. Note that the display refresh is not program controlled. This can be verified by the fact that you can see my screen dissolver working as it runs (I make no effort to update the display in my code). I suspect that the display controller operates in one of the following modes: 1. Display controller is supplied with an timing signal from the hardware timer (directly or indirectly through some interrupt) every 64th of a second or so, at which time the display controller does DMA, reading the memory and updating the display with the information. 2. There is a generic interrupt generated by the hardware timer every 64th of a second or so. The handler for that interrupt then manually writes the appropriate registers to push the image data onto the display one nibble at a time. Note that this implies the existence of a display "data register" which, when written, puts the written data directly on the screen. I have seen no evidence of such a register, so I am skeptical as to whether this is really done. I am guessing at the 64th of a second screen refresh based on the way it flickers under flourescent lighting, which operates at 60 Hz. Of course, I make no guarantees as to the accuracy of the above information, although I believe it to be correct. Still, be sure to verify any of the above information through your own experimentation before using it. >>>Joe