Interchip

So in WARG, we have two chips:

  • The Autopilot Chip
  • The Safety Chip

On the safety chip, we have everything needed to perform basic manual flight. On the other hand, the Autopilot chip is where the “intelligence” comes from, that is, the part responsible for autonomous navigation.

The modules that allows autopilot to communicate with Safety is called Interchip. It uses the SPI and various Hardware Abstraction Layer

So we start with Interchip_Init, HAL has a bunch of library functions.

The code runs on top of FreeRTOS.

Interchip_A (explained)

As we have said, we are using SPI, which is active_low (the CS/SS line should only be set to 0 when we are actively transferring data). This is what we are doing when we first initialize the interchip with interchip_init by setting the Register to 1 (high).

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

After interchip is initialized, we can call interchip_run everytime we want to exchange data, so now. Under interchip_run, we we set the Register to 0 (active-low) as we are exchanging data now. We use this HAL function with SPI that enables both rx and tx.

We combine it with an interrupt (ISR), and so when its done, the HAL library will call the interrupt.

At this point, it is important to understand how Interrupts work. Basically, they’re kinda like cronjobs (scheduled tasks with top priority). So when tx and rx are done, we call the interrupt. We can go into the callbacks.c (the interrupt stuff) and then that calls the function interchipTxRxCallback() because we are done the write, so now there is new data so set the flag to true. At this point, we are done writing, so we write pin as 1 again.

The actual data itself is in the form of PWM values. If you look at the struct of the data, you see its array of 12 different PWM values. You can think of each PWM value as a different channel. So for example, PWM[3] is to set the gimbal percent pitch.

typedef struct {
	uint16_t safetyLevel;
	int16_t PWM[12];
} Interchip_Packet;  

We use interchip_setPWM to set the values for a particular channel.look at the function SendToSatefy_Execute → (this is where AtittudeManager prepares the final data to be sent to interchip, it takes in a channel)

In terms of how sending data actually works, this is taken care by the SPI protocol. It’s “peripheral to memory”. I was being explained this by Chris Chung and the use of Register but still not perfectly familiar.

Interchip_S (Explained)

The interchip on the safety side is very similar.

Implementation with DMA

So now, we want to use DMA instead of CPU to do all of this task.

#include "Interchip_A.h"
#include "cmsis_os.h"
#include "spi.h"
 
static volatile Interchip_Packet rxData;
static volatile Interchip_Packet txData;
static volatile bool dataNew;
 
// freertos run function
 
void Interchip_Run() {
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
	HAL_StatusTypeDef result = HAL_SPI_TransmitReceive_IT(&hspi6,(uint8_t *)&txData,(uint8_t *)&rxData, 26);
}
 
// We initialize Interchip. Set the pin to 1 to say that we are not writing to anything
void Interchip_Init() {
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  // the rest of this program is just for like,
  txData.safetyLevel = 14;
  txData.PWM[0] = 0;
	txData.PWM[1] = 0; 
	txData.PWM[2] = 0;
	txData.PWM[3] = 0;
	txData.PWM[4] = 0;
	txData.PWM[5] = 0;
	txData.PWM[6] = 0;
	txData.PWM[7] = 0;
	txData.PWM[8] = 0;
	txData.PWM[9] = 0;
	txData.PWM[10] = 0;
	txData.PWM[11] = 0;
}
 
 
// Sets a PWM channel
void Interchip_SetPWM(int index,int data) {
	HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
	txData.PWM[index] = (int16_t) data;
}
 
// returns the safetyLevel
uint16_t Interchip_GetAutonomousLevel(void) {
  dataNew = false;
  return rxData.safetyLevel; 
}
 
// called during the SPI TxRx interrupt
void InterchipTxRxCallback() { //GPIO_PIN_Set = 1, because we are done writing 
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	dataNew = true;
}
 
// returns the dataNew variables state
uint8_t InterchipIsDataNew() {
	if (dataNew) {
		return 1;
	} 
	return 0;
}