316 lines
13 KiB
ObjectPascal
316 lines
13 KiB
ObjectPascal
|
{
|
||
|
beamer.pas
|
||
|
|
||
|
The beamer controller polls the UART to get commands and provides the
|
||
|
corresponding replies.
|
||
|
}
|
||
|
|
||
|
program BeamerControl;
|
||
|
|
||
|
{==============================================================================}
|
||
|
{ Constants }
|
||
|
{==============================================================================}
|
||
|
const
|
||
|
clockFrequency = 66E6;
|
||
|
gpioBaseAddress = $0000;
|
||
|
gpioDataOffset = $0000;
|
||
|
gpioEnableOffset = $0001;
|
||
|
uartBaseAddress = $0010;
|
||
|
uartBaudOffset = $0002;
|
||
|
uartStatusOffset = $0001;
|
||
|
uartDataReady = $0001;
|
||
|
uartSending = $0002;
|
||
|
uartBaudRate = 1E6;
|
||
|
uartBaudCount = clockFrequency / uartBaudRate;
|
||
|
uartpollDelay = uartBaudCount / 2;
|
||
|
commandHeader = $AA;
|
||
|
commandNack = $00;
|
||
|
commandWriteMem = $03;
|
||
|
commandReadMem = $04;
|
||
|
commandWriteLength = 4;
|
||
|
commandReadLength = 2;
|
||
|
beamerBaseAddress = $0020;
|
||
|
beamerCtlOffset = $0000;
|
||
|
beamerSpeedOffset = $0001;
|
||
|
beamerCtlInit = $0401;
|
||
|
beamerSpeedInit = $0004;
|
||
|
|
||
|
{==============================================================================}
|
||
|
{ Variables }
|
||
|
{==============================================================================}
|
||
|
var
|
||
|
packetId, commandId, errorId: uint8;
|
||
|
memoryAddress, memoryData: word;
|
||
|
|
||
|
{==============================================================================}
|
||
|
{ Procedures and functions }
|
||
|
{==============================================================================}
|
||
|
|
||
|
{============================================================================}
|
||
|
{ Register-level accesses }
|
||
|
{============================================================================}
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Registers initializations }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
procedure initRegisters;
|
||
|
begin
|
||
|
{ initialize GPIO }
|
||
|
mem[gpioBaseAddress+gpioDataOffset] := $AA;
|
||
|
mem[gpioBaseAddress+gpioEnableOffset] := $0F;
|
||
|
{ initialize UART }
|
||
|
mem[uartBaseAddress+uartBaudOffset] := uartBaudCount;
|
||
|
{ initialize beamer peripheral }
|
||
|
mem[beamerBaseAddress+beamerCtlOffset] := beamerCtlInit;
|
||
|
mem[beamerBaseAddress+beamerSpeedOffset] := beamerSpeedInit;
|
||
|
end;
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Get byte from serial port }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
procedure getSerialPortByte : uint8;
|
||
|
var
|
||
|
uartByte: uint8;
|
||
|
begin
|
||
|
{ poll until data byte available }
|
||
|
uartByte := 0;
|
||
|
while uartByte = 0 do
|
||
|
begin
|
||
|
{ spend time in order not to overcharge the AHB bus }
|
||
|
for index := 1 to uartpollDelay do
|
||
|
noOperation;
|
||
|
{ read status register }
|
||
|
uartByte := mem[uartBaseAddress+uartStatusOffset] and uartDataReady;
|
||
|
end;
|
||
|
{ read data register and return it }
|
||
|
getSerialPortByte := mem[uartBaseAddress];
|
||
|
end;
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Send byte to serial port }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
procedure sendSerialPort(uartByte : uint8);
|
||
|
var
|
||
|
statusByte: uint8;
|
||
|
begin
|
||
|
{ poll until ready to send }
|
||
|
statusByte := mem[uartBaseAddress+uartStatusOffset] and uartSending;
|
||
|
while statusByte = 0 do
|
||
|
begin
|
||
|
{ spend time in order not to overcharge the AHB bus }
|
||
|
for index := 1 to uartpollDelay do
|
||
|
noOperation;
|
||
|
{ read status register }
|
||
|
statusByte := mem[uartBaseAddress+uartStatusOffset] and uartSending;
|
||
|
end;
|
||
|
{ write data register }
|
||
|
mem[uartBaseAddress] := uartByte;
|
||
|
end;
|
||
|
|
||
|
{============================================================================}
|
||
|
{ Communication protocol }
|
||
|
{============================================================================}
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Get command }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
function getCommand(
|
||
|
var packetId, commandId, commandLength : uint8;
|
||
|
var memoryAddress, memoryData : word
|
||
|
) : uint8;
|
||
|
var
|
||
|
uartData: uint8;
|
||
|
checksum: word;
|
||
|
begin
|
||
|
{ wait for new command header }
|
||
|
uartData := 0;
|
||
|
while uartData <> commandHeader do
|
||
|
uartData := getSerialPortByte;
|
||
|
checksum := uartData;
|
||
|
{ get packet id }
|
||
|
packetId := getSerialPortByte;
|
||
|
checksum := checksum + packetId;
|
||
|
{ get command }
|
||
|
commandId := getSerialPortByte;
|
||
|
checksum := checksum + commandId;
|
||
|
{ process known commands }
|
||
|
if (commandId = commandWriteMem) or (commandId = commandReadMem) then
|
||
|
begin
|
||
|
{ get command length }
|
||
|
commandLength := getSerialPortByte;
|
||
|
checksum := checksum + commandLength;
|
||
|
{ check command lengths }
|
||
|
if (commandId = commandWriteMem) and (commandLength <> commandWriteLength) then
|
||
|
getCommand := 1;
|
||
|
else if (commandId = commandReadMem) and (commandLength <> commandReadLength) then
|
||
|
getCommand := 1;
|
||
|
else
|
||
|
begin
|
||
|
{ get address }
|
||
|
memoryAddress := getSerialPortByte;
|
||
|
checksum := checksum + memoryAddress;
|
||
|
memoryAddress := (memoryAddress shl 8) + getSerialPortByte;
|
||
|
checksum := checksum + memoryAddress;
|
||
|
{ get data }
|
||
|
if commandId = commandReadMem then
|
||
|
begin
|
||
|
memoryData := getSerialPortByte;
|
||
|
checksum := checksum + memoryData;
|
||
|
memoryData := (memoryData shl 8) + getSerialPortByte;
|
||
|
checksum := checksum + memoryData;
|
||
|
end;
|
||
|
{ get and verify checksum}
|
||
|
if getSerialPortByte = (checksum and $00FF) then
|
||
|
getCommand := 0;
|
||
|
else
|
||
|
getCommand := 1;
|
||
|
end;
|
||
|
end;
|
||
|
else
|
||
|
getCommand := 1;
|
||
|
end;
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Send NACK }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
function sendNegativeAcknowledge(packetId : uint8);
|
||
|
var
|
||
|
uartData: uint8;
|
||
|
checksum: word;
|
||
|
begin
|
||
|
{ send packet header }
|
||
|
uartData := $AA;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := uartData;
|
||
|
{ send packet id }
|
||
|
uartData := packetId;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send command id }
|
||
|
uartData := commandNack;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send packet length }
|
||
|
uartData := 0;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send checksum }
|
||
|
uartData := checksum and $00FF;
|
||
|
sendSerialPort(uartData);
|
||
|
end;
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Send ACK }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
function sendAcknowledge(packetId, commandId : uint8);
|
||
|
var
|
||
|
uartData: uint8;
|
||
|
checksum: word;
|
||
|
begin
|
||
|
{ send packet header }
|
||
|
uartData := $AA;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := uartData;
|
||
|
{ send packet id }
|
||
|
uartData := packetId;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send command id }
|
||
|
uartData := commandId;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send packet length }
|
||
|
uartData := 0;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send checksum }
|
||
|
uartData := checksum and $00FF;
|
||
|
sendSerialPort(uartData);
|
||
|
end;
|
||
|
|
||
|
{----------------------------------------------------------------------------}
|
||
|
{ Send READ_MEM reply }
|
||
|
{----------------------------------------------------------------------------}
|
||
|
function sendReadAnswer(packetId : uint8; memoryData: word);
|
||
|
var
|
||
|
uartData: uint8;
|
||
|
checksum: word;
|
||
|
begin
|
||
|
{ send packet header }
|
||
|
uartData := $AA;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := uartData;
|
||
|
{ send packet id }
|
||
|
uartData := packetId;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send command id }
|
||
|
uartData := commandReadMem;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send packet length }
|
||
|
uartData := 2;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send data low }
|
||
|
uartData := memoryData and $00FF;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send data high }
|
||
|
uartData := memoryData shr 8;
|
||
|
sendSerialPort(uartData);
|
||
|
checksum := checksum + uartData;
|
||
|
{ send checksum }
|
||
|
uartData := checksum and $00FF;
|
||
|
sendSerialPort(uartData);
|
||
|
end;
|
||
|
|
||
|
{==============================================================================}
|
||
|
{ Main program }
|
||
|
{==============================================================================}
|
||
|
begin
|
||
|
{ initialize SoC registers }
|
||
|
initRegisters;
|
||
|
{ main loop }
|
||
|
while true do begin
|
||
|
{ get a new command }
|
||
|
errorId := getCommand(packetId, commandId, memoryAddress, memoryData);
|
||
|
{ process command }
|
||
|
if errorId = 0 then
|
||
|
begin
|
||
|
{ process write command }
|
||
|
if commandId = commandWriteMem then
|
||
|
begin
|
||
|
mem[memoryAddress] := memoryData;
|
||
|
sendAcknowledge(packetId, commandId);
|
||
|
end;
|
||
|
{ process read command }
|
||
|
else if commandId = commandReadMem then
|
||
|
begin
|
||
|
memoryData := mem[memoryAddress];
|
||
|
sendReadAnswer(packetId, memoryData);
|
||
|
end;
|
||
|
{ reply to unknown command }
|
||
|
else
|
||
|
sendNegativeAcknowledge(packetId);
|
||
|
end;
|
||
|
{ negative acknowledge on reception error }
|
||
|
else
|
||
|
sendNegativeAcknowledge(packetId);
|
||
|
end;
|
||
|
end.
|
||
|
|
||
|
{
|
||
|
;---------------------------------------------------------------
|
||
|
; register definitions
|
||
|
; s0, s1: used for INPUT and OUTPUT operations
|
||
|
; S2: returns UART data byte
|
||
|
; S3: uart protocol checksum
|
||
|
; S4: uart protocol packet id
|
||
|
; S5: uart protocol command id
|
||
|
; S6: uart protocol address
|
||
|
; S7: uart protocol data
|
||
|
; S8: copy of UART data byte for debug
|
||
|
;---------------------------------------------------------------
|
||
|
}
|