369 lines
14 KiB
ObjectPascal
369 lines
14 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;
|
|
uartTimeout = 10;
|
|
commandHeader = $AA;
|
|
commandNack = $00;
|
|
commandWriteMem = $03;
|
|
commandReadMem = $04;
|
|
commandWriteLength = 4;
|
|
commandReadLength = 2;
|
|
beamerBaseAddress = $0020;
|
|
beamerCtlOffset = $0000;
|
|
beamerSpeedOffset = $0001;
|
|
beamerCtlInit = $0401;
|
|
beamerSpeedInit = $0004;
|
|
commStIdle = $0000;
|
|
commStGetPacketId = $0001;
|
|
commStGetCommandId = $0002;
|
|
commStGetDataLength = $0003;
|
|
commStGetData = $0004;
|
|
commStGetChecksum = $0005;
|
|
commStExecuteCommand = $0006;
|
|
commStSendHeader = $0007;
|
|
commStSendPacketId = $0008;
|
|
commStSendCommandId = $0009;
|
|
commStSendDataLength = $000A;
|
|
commStSendData = $000B;
|
|
commStSendChecksum = $000C;
|
|
|
|
{==============================================================================}
|
|
{ Variables }
|
|
{==============================================================================}
|
|
var
|
|
communicationState : word;
|
|
uartByte: uint8;
|
|
|
|
{==============================================================================}
|
|
{ Procedures and functions }
|
|
{==============================================================================}
|
|
|
|
{============================================================================}
|
|
{ Register-level functions }
|
|
{============================================================================}
|
|
|
|
{----------------------------------------------------------------------------}
|
|
{ Registers initializations }
|
|
{----------------------------------------------------------------------------}
|
|
procedure initRegisters;
|
|
const
|
|
gpioValue = $AA;
|
|
gpioEnablemask = $0F;
|
|
begin
|
|
{ initialize GPIO }
|
|
mem[gpioBaseAddress+gpioDataOffset] := gpioValue;
|
|
mem[gpioBaseAddress+gpioEnableOffset] := gpioEnablemask;
|
|
{ initialize UART }
|
|
mem[uartBaseAddress+uartBaudOffset] := uartBaudCount;
|
|
{ initialize beamer peripheral }
|
|
mem[beamerBaseAddress+beamerCtlOffset] := beamerCtlInit;
|
|
mem[beamerBaseAddress+beamerSpeedOffset] := beamerSpeedInit;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
{ Get byte from serial port with timeout }
|
|
{----------------------------------------------------------------------------}
|
|
function getSerialPortByte(var uartByte: uint8) : word;
|
|
var
|
|
dataReady: uint8;
|
|
pollCount: word;
|
|
begin
|
|
{ poll until data byte available or timeout occured}
|
|
pollCount := uartPollDelay;
|
|
dataReady := 0;
|
|
while dataReady = 0 do
|
|
begin
|
|
{ read status register }
|
|
dataReady := mem[uartBaseAddress+uartStatusOffset] and uartDataReady;
|
|
{ spend time in order not to overcharge the AHB bus }
|
|
if dataReady = 0 then
|
|
begin
|
|
{ check for timeout }
|
|
pollCount := pollCount -1;
|
|
if pollCount = 0 then
|
|
dataReady := $FF;
|
|
{ spend time in order not to overcharge the system bus }
|
|
for index := 1 to uartPollDelay do
|
|
noOperation;
|
|
end;
|
|
end;
|
|
{ function return }
|
|
if dataReady = $FF then
|
|
{ return timeout }
|
|
getSerialPortByte := 1;
|
|
else
|
|
{ read data register and return it }
|
|
begin
|
|
uartByte := mem[uartBaseAddress];
|
|
getSerialPortByte := 0;
|
|
end;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
{ Send byte to serial port with timeout }
|
|
{----------------------------------------------------------------------------}
|
|
function sendSerialPort(var uartByte : uint8) : word;
|
|
var
|
|
dataReady: uint8;
|
|
statusByte: uint8;
|
|
pollCount: word;
|
|
begin
|
|
{ poll until ready to send }
|
|
pollCount := uartPollDelay;
|
|
statusByte := mem[uartBaseAddress+uartStatusOffset] and uartSending;
|
|
while statusByte = 0 do
|
|
begin
|
|
{ check for timeout }
|
|
pollCount := pollCount -1;
|
|
if pollCount = 0 then
|
|
dataReady := $FF;
|
|
{ spend time in order not to overcharge the system bus }
|
|
for index := 1 to uartPollDelay do
|
|
noOperation;
|
|
{ read status register }
|
|
statusByte := mem[uartBaseAddress+uartStatusOffset] and uartSending;
|
|
end;
|
|
{ function return }
|
|
if dataReady = $FF then
|
|
{ return timeout }
|
|
sendSerialPort := 1;
|
|
else
|
|
{ write data register and return it }
|
|
begin
|
|
mem[uartBaseAddress] := uartByte;
|
|
sendSerialPort := 0;
|
|
end;
|
|
end;
|
|
|
|
{============================================================================}
|
|
{ Communication state machine }
|
|
{============================================================================}
|
|
procedure updateStateMachine(
|
|
var communicationState : word;
|
|
var uartByte: uint8
|
|
);
|
|
var
|
|
communicationNextState : word;
|
|
uartStatus: word;
|
|
packetId, commandId : uint8;
|
|
checksum : uint8;
|
|
dataLength, dataCount, data1, data2, data3, data4 : uint8;
|
|
memAddress, memData : word;
|
|
begin
|
|
{ idle }
|
|
if communicationState = commStIdle then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if (uartStatus = 0) and (uartByte = commandHeader) then
|
|
begin
|
|
checksum := uartByte;
|
|
communicationNextState := commStGetPacketId;
|
|
end;
|
|
end;
|
|
{ get packet id }
|
|
else if communicationState = commStGetPacketId then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
packetId := uartByte;
|
|
checksum := checksum + uartByte;
|
|
communicationNextState := commStGetCommandId;
|
|
end;
|
|
end;
|
|
{ get command id }
|
|
else if communicationState = commStGetCommandId then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
commandId := uartByte;
|
|
checksum := checksum + uartByte;
|
|
communicationNextState := commStGetDataLength;
|
|
end;
|
|
end;
|
|
{ get data length }
|
|
else if communicationState = commStGetDataLength then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
dataLength := uartByte;
|
|
checksum := checksum + uartByte;
|
|
dataCount := dataLength;
|
|
communicationNextState := commStGetData;
|
|
end;
|
|
end;
|
|
{ get data }
|
|
else if communicationState = commStGetData then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
data1 := data2;
|
|
data2 := data3;
|
|
data3 := data4;
|
|
data4 := uartByte;
|
|
checksum := checksum + uartByte;
|
|
dataCount := dataCount-1;
|
|
if dataCount = 0 then
|
|
communicationNextState := commStGetChecksum;
|
|
end;
|
|
end;
|
|
{ get checksum }
|
|
else if communicationState = commStGetChecksum then
|
|
begin
|
|
uartStatus := getSerialPortByte(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
if uartByte = checksum then
|
|
communicationState := commStExecuteCommand;
|
|
else
|
|
begin
|
|
commandId := commandNack;
|
|
dataLength := 0;
|
|
communicationNextState := commStSendHeader;
|
|
end;
|
|
end;
|
|
end;
|
|
{ execute command }
|
|
else if communicationState = commStExecuteCommand then
|
|
begin
|
|
if (commandId = commandWriteMem) and (dataLength = commandWriteLength) then
|
|
begin
|
|
memAddress := data1 + (data2 shl 8);
|
|
memData := data3 + (data4 shl 8);
|
|
mem[memAddress] := memData;
|
|
dataLength := 0;
|
|
communicationNextState := commStSendHeader;
|
|
end;
|
|
else if (commandId = commandReadMem) and (dataLength = commandReadLength) then
|
|
begin
|
|
memAddress := data3 + (data4 shl 8);
|
|
memData := mem[memAddress];
|
|
dataLength := 2;
|
|
data1 := memData and $00FF;
|
|
data2 := memData shr 8;
|
|
communicationNextState := commStSendHeader;
|
|
end;
|
|
else
|
|
begin
|
|
commandId := commandNack;
|
|
dataLength := 0;
|
|
communicationNextState := commStSendHeader;
|
|
end;
|
|
end;
|
|
{ send header }
|
|
else if communicationState = commStSendHeader then
|
|
begin
|
|
uartByte := commandHeader;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
checksum := uartByte;
|
|
communicationNextState := commStSendPacketId;
|
|
end;
|
|
end;
|
|
{ send packet id }
|
|
else if communicationState = commStSendPacketId then
|
|
begin
|
|
uartByte := packetId;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
checksum := checksum + uartByte;
|
|
communicationNextState := commStSendCommandId;
|
|
end;
|
|
end;
|
|
{ send command id }
|
|
else if communicationState = commStSendCommandId then
|
|
begin
|
|
uartByte := commandId;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
checksum := checksum + uartByte;
|
|
communicationNextState := commStSendDataLength;
|
|
end;
|
|
end;
|
|
{ send data length }
|
|
else if communicationState = commStSendDataLength then
|
|
begin
|
|
uartByte := dataLength;
|
|
dataCount := dataLength;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
checksum := checksum + uartByte;
|
|
communicationNextState := commStSendData;
|
|
end;
|
|
end;
|
|
{ send data }
|
|
else if communicationState = commStSendData then
|
|
begin
|
|
if dataCount > 0 then
|
|
begin
|
|
uartByte := data1;
|
|
data2 := data1;
|
|
data3 := data2;
|
|
data4 := data3;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
begin
|
|
checksum := checksum + uartByte;
|
|
dataCount := dataCount-1;
|
|
end;
|
|
end;
|
|
else
|
|
communicationNextState := commStSendChecksum;
|
|
end;
|
|
{ send checksum }
|
|
else if communicationState = commStSendChecksum then
|
|
begin
|
|
uartByte := checksum and $00FF;
|
|
uartStatus := sendSerialPort(var uartByte: uint8);
|
|
if uartStatus = 0 then
|
|
communicationNextState := commStIdle;
|
|
end;
|
|
{ update state }
|
|
communicationState := communicationNextState;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
{ Main program }
|
|
{==============================================================================}
|
|
begin
|
|
{ initialize SoC registers }
|
|
initRegisters;
|
|
{ initialize communication state machine }
|
|
communicationState := commStIdle;
|
|
{ main loop }
|
|
while true do begin
|
|
{ update communication state machine }
|
|
updateStateMachine(var communicationState : word; var uartByte : uint8);
|
|
{ check for timeout }
|
|
end;
|
|
end.
|