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
 | 
						|
                ;---------------------------------------------------------------
 | 
						|
}
 |