Control Panel Notes
The 8 devices share a single 8 bit IO port on a PIC microcontroller. The device is selected by a 3 bit wide select line. The devices we speak of here are only for clairity's sake. In the actual control panel, some of the logical devices (such as the seven segment display) have more than 8 bits of IO and some (such a button or LED) have fewer. Another way of thinking about it: there are 64 "virtual" IO lines that are compressed down to 11 (8+3) then reexpanded. A device may use any configuration of IO lines in the 8x8 grid. They are used for the following:
- 5 digit 7 segment LED display
- 3 digit BCD thumbwheel
- 5 playlist buttons (including Push it to the Limit)
- 2 toggle switches for arming
- 7 LEDs: 2 for arming, 5 for playlists
- 2 IO and 1 input for future expansion
The software is based around the IO Buffer which maps the 64 virtual IO lines to an 8x8 chunk of memory. The timer and interrupt make sure that the buffer remains up to date without the user needing to add code to the main loop or manipulate the IO ports directly.
The PIC softwaer, written entirely in assembler, is divided into these components:
- IO buffer - multiplexes IO port to create virtual memory-mapped IO lines
- Serial buffer - packs data in the transmit buffer into a 4E Network packet and sends it, buffers recieved data and parses it into the header and data
- Timer and 7 segment display - times how long it has been since the last time a playlist button was pushed
- Combination lock - reads the BCD thumbwheels and compares it to a preset combination. The playlist buttons only work if the correct combination was entered.
- Playlist buttons - pushing one of these buttons sends a message to the Bemix server instructing it to load a certain song, such as Push it to the Limit.
- Message handler - act on requests coming over the 4E network.
Multiplexes an IO port specified by DATA_PORT 8 ways to create 64 virtual, memory-mapped IO lines. Each time RefreshIOBuffer is called, IOBufferCounter is incremented. IOBufferCounter mod 8 (the 3 least significant bits) is output on the select port and IOBuffer[IOBufferCounter%8] is output on the data port. RefreshIOBuffer should be placed in the timer interrupt so that it will be called regularly and will be transparent to the user.
- DATA_PORT - the data port
- DATA_TRIS - the TRIS register for the data port
- SEL_PORT - which port the 3 select lines are on; which IO lines are used is hard coded
- IOBuffer - an 8 byte chunk of memory that can be written or read (depending on IOBufferTris) that maps to the 64 virtual IO lines.
- IOBufferTris - an 8 byte chunk of memory used to set the "tris" on each of the virtual 64 IO lines. May be changed at any point in the program. 0=Output, 1=Input.
- IOBufferCounter - used to keep track of which device to address.
- RefreshIOBuffer - the routine that updates IOBuffer and the port. Needs to be placed in the timer ISR.
The serial buffer consists of a transmit and a recieve buffer. To transmit a packet, the data is written to TxBuffer, either manually or, preferably, using putTxBuffer. When transmit is called, the header is generated and the entire packet is transmitted. Reception is done in a similar fashion. Each time a byte is recieved, it is put into the RxBuffer. When a header code is recieved, the buffer is cleared. This forces byte 0 of the packet (minus the header code) into RxBuffer, etc. When the end code is recived, the destination address is checked. If it matches ADDRESS (ie, the packet is to this device), rcvPacket is called to process the packet. This function dispatches based on the port number. See 4E Network for more information.
- ADDRESS - the address of this device
- putTxBuffer - adds a byte to the end of the TxBuffer
- transmit - transmits TxBuffer
- handleRecieve - adds bytes to RxBuffer as they come in, parses the header and determines if the packet is addressed to ADDRESS
- rcvPacket - this user supplied function is called when a valid packet is revieced
Timer and Display
The timer is a six counter with user selectable digit rollovers, up to F. With properly selected values, the counter behaves like a clock with hours, minutes, and seconds. The time is stored in three bytes; each digit has four bits. In order to be sure that each nibble always has a valid value, the counter should be incremented with incrementTimer. The 3 counter bytes can also be manually written with care.
The seven segment display codes are generated from the counter using a lookup table.
The timer and seven segment conversion are encapsulated in refreshTimer. This function reads timerStatus and preforms the requested operations, then sets appropriate flags in the register. RefreshTimer should be called at regular intervals.
- rollover values for each digit
- TIMER_CAL - a 0-255 value used to calibrate the timer
- timerStatus - a register that specifies the state of the timer.
- start - 1: timer is running
- show - 1: display the timer on the 7 segment display
- overflow - 1: the timer has overflown
- Hour, Min, Sec - a 3 byte block of memory. Each nibble represents a digit to be displayed, except the more signigicant nibble of Hour.
- TimerCount - incremented every time refreshTimer is called, increments sec when matches TIMER_CAL.
- refreshTimer - does the operations specified by TimerStatus. Needs to be placed in the timer ISR.
- HexTo7Seg - converts a nibble to a 7 bit 7 segment display code.