Dec 23

Processing a command that writes data from the FB to the PMC is very straight forward:

  • Set the data bus to output (if not done already)
  • Set the 1’s of the command (address) and data pins
  • Set the 0’s of the command and data pins including the low level of the /WR pin
  • Repeat this process for each data byte of the command

Since the falling edge of the /WR pin on the PMC triggers an ISR and the write speed of the FB is limited to 10.8us (46kHz*2) per set or clear cycle there is no need to worry that data will be lost. The moment the ISR is triggered, the data is available on the data bus, so the ISR does not have to include any delay which will block the whole system (including the RoboCAN interface). 

Since the command is received in an ISR and ISR’s should consume the least possible amount of time, processing the command received can only be part of the ISR if it sets or clears some variables. Any action that would require (for example) communication using the RoboCAN interface should be executed outside the ISR as part of the main application. Remember that a command over the RoboCAN interface might take several milli seconds in case the interface is busy or the received does not respond.

Processing a command that reading data is by definition more complex since there is a “slow” device (the FB) that needs to copy the data from the databus.  

  • Set the data bus to input (if not done already)
  • Set the 1’s of the command (address)
  • Set the 0’s of the command including the low level of the /RD pin
  • Read the data pins and store them
  • Repeat this process for each data byte of the command

Since it takes 10.8us for the FB to read the data (if not blocked by other processes) it means the PMC is stuck in the ISR linked to the falling edge of the /RD signal. One option is to leave the data on the bus and simply exit the ISR. This can (will) however create bus conflicts the moment the FB decides to write data.

In a normal bus system the slave places data on the bus at the falling edge of /RD and removes it on the rising edge of /RD. The best solution than is to trigger the ISR on each edge and decide what to do the moment the ISR is executed. The AT90CAN128 supports this behavior, it can trigger the interrupt on any logical change.

As a result, a falling edge on /RD will place the data on the bus and exit the ISR. At the rising edge of /RD the data is removed, final question to answer is when to generate the rising edge? If it is part of the read function on the FB it will require an additional IO call at the end of the read function (reading more bits will automatically raise /RD when the 1’s of the command are set). If this is not done, than the /RD will remain low until the next read or write command. This is not prefer ed since if a write follows the /RD pins is raised but the data lines are already reversed before this raise and so creating a bus conflict.

The big question is how much time the AT90CAN128 needs to prepare the data and set the first byte of this data on the bus. If this is not finished before the FB copies the data from the data lines than we have a problem. Based on the 10.8us for an IO call on the FB I don’t for see any problem as long as (again) filling the data to return does not include any calls on the AT90CAN128 other than copying existing known data into the buffer. Also the interrupt used is the second highest available interrupt source on the AT90CAN128. The highest is for the /WR signal, since the FB can not read and write at the same time there is no difference in the priorities, if /RD is lowered (or raised) the ISR will be called directly unless it is stuck into another ISR. This will be the first thing to check if strange data is read back.

For the /WR signal it is good enough to trigger only on the falling edge, but it makes sense to trigger on any level change as well to enable of disable the communication LED. To prevent reacting on undefined states when the FOXBoard is still booting or when the SnakeBot application is not started or starting the PMC needs to ignore any change until it detects a stable state (/RD is high and /WR is high).

While implementing the first command to set a power mode on the PMC I already struggle with processing this command inside the ISR. It will require commands send to the various actuators, so the command must be buffered and executed as part of the main program and not inside the ISR. Sending a command from the PMC to the FB is not interrupt based, so only received commands need to be buffered.

Claiming an array of command structures is not memory friendly, instead a simple circular buffer will do the trick in which the command (2 bytes), the amount if data bytes (1 byte) and the data (x) bytes can be stored. Two command pointers (one points to the next to read and one points to the first free position) do the maintenance of the buffer. This buffer is called CommandBuffer and made 128 bytes long. Time will tell if this is enough. Two functions are defined; StoreCommand and GetCommand. The first is now called when a full command is received in the /RD ISR. The application can call the function CommandReceived to check if a command is available in the buffer or simple call GetCommand which will fail if no command is available.

Here is the latest version of the PMC code. Here is the latest version of the FB test program.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.