groupgets / purethermal1-firmware

Reference firmware for PureThermal 1 FLIR Lepton Dev Kit
MIT License
125 stars 62 forks source link

Migrating code to work with nucleo stm32f401re #1

Closed Yuval-Toren closed 8 years ago

Yuval-Toren commented 8 years ago

HI,

I am trying to migrate the purethermal 1 code to work with my nucleo stm32f401re but its so large and complicated and i cant seem to understand how it works or what to do in order to make it work on my nucleo. I tried taking only the spi part and puting it inside a cubemx code i generated but with no succes. all i need is the spi part, or in other words - to read the camera from the spi and sending the data to the computer through uart in a good frame rate.

any suggestion how i should do it?

any help will be welcome, thanks

kekiefer commented 8 years ago

Hi @mechashef --

Without reviewing how the nucleo code works (or if it using the HAL libraries), my guess is the whole download is trying to happen with the CPU-based SPI receive routine.

To get this to work well, we use a CPU-based transfer to get in sync the first line of the image, and then use DMA to transfer the rest. This works very well. See Src/lepton.c for the entire lepton transfer routine.

You'll need to configure a DMA channel that works with correct SPI peripheral's receive. The PureThermal 1 uses SPI2 for transferring lepton data. For SPI2 the associated DMA is DMA1 stream 3. SPI1 will be DMA2 stream 0 or 2. If the nucleo example is based on CubeMX, this will be easier to get set up since you can just use the eclipse GUI to configure the peripheral. But you can probably find the relevant bits in this source code, all the SPI and DMA initialization happens in Src/stm32f4xx_hal_msp.c

Alternatively, you could probably use SPI interrupt transfers to get the data, that might be easier. Or just get yourself a PureThermal 1 module! ;)

Yuval-Toren commented 8 years ago

Hi @kekiefer ,

I tried what you said but seems like i can never reach Synchronization with the camera which is weird- the code is simple :

#define IMAGE_NUM_LINES 60

#define LEPTON_ADDRESS  (0x2A<<1)

#define POWER_REG (0x00)
#define STATUS_REG (0x02)
#define COMMAND_REG (0x04)
#define DATA_LENGTH_REG (0x06)
#define DATA_0_REG (0x08)
#define DATA_CRC_REG (0x28)

#define AGC (0x01)
#define SYS (0x02)
#define VID (0x03)
#define OEM (0x48)

#define GET (0x00)
#define SET (0x01)
#define RUN (0x02)

#define PING                        (0x00 )
#define CAM_STATUS                  (0x04 )
#define FLIR_SERIAL_NUMBER          (0x08 )
#define CAM_UPTIME                  (0x0C )
#define AUX_TEMPERATURE_KELVIN      (0x10 )
#define FPA_TEMPERATURE_KELVIN      (0x14 )
#define TELEMETRY_ENABLE_STATE      (0x18 )
#define TELEMETRY_LOCATION          (0x1C )
#define EXECTUE_FRAME_AVERAGE       (0x20 )
#define NUM_FRAMES_TO_AVERAGE       (0x24 )
#define CUST_SERIAL_NUMBER          (0x28 )
#define SCENE_STATISTICS            (0x2C )
#define SCENE_ROI                   (0x30 )
#define THERMAL_SHUTDOWN_COUNT      (0x34 )
#define SHUTTER_POSITION            (0x38 )
#define FFC_SHUTTER_MODE_OBJ        (0x3C )
#define RUN_FFC                     (0x42 )
#define FFC_STATUS                  (0x44 )

#define VOSPI_FRAME_SIZE 164
uint8_t Lep_Img[60][160];
uint8_t header[4];

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* Private function prototypes -----------------------------------------------*/

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();

  uint8_t packet[VOSPI_FRAME_SIZE*IMAGE_NUM_LINES];
  HAL_StatusTypeDef status;
  HAL_Delay(185);

  do {
          if ((status = HAL_SPI_Receive(&hspi1, packet, VOSPI_FRAME_SIZE,200)) != HAL_OK)
          {
             printf("error");
             HAL_Delay(200);
          }
        } while ((packet[0] & 0x0f) == 0x0f);

  while (1)
  {
      HAL_SPI_Receive_DMA(&hspi1, packet , VOSPI_FRAME_SIZE);
      if(packet[0]& 0x0f != 0x0f)
      {
      HAL_UART_Transmit(&huart1,&packet[1],1,1000);
      }
      else
      {
          HAL_Delay(200);
      }

  }

}
kekiefer commented 8 years ago

Is the SPI peripheral configured the same?

Yuval-Toren commented 8 years ago

yes

kekiefer commented 8 years ago

I've reviewed in detail @mechashef and I see a number of fundamental issues.

  1. You need to sync the first line with the cpu transfer at the start of each frame, not just the start of the program
  2. After the first line is synced, the DMA transfer should pull down the remainder of the lines, so this is VOSPI_FRAME_SIZE * (IMAGE_NUM_LINES - 1). And you need to offset into your frame buffer by the size of the one line you transfered via cpu.
  3. Note that the DMA transfer is asynchronous, you need to wait for it to complete (best set up an interrupt to be notified of this) before you can check data in the buffer.
  4. At the end of the entire transfer, you should check that the last line's number is 59. If it is, you can do something with the data, if not, you should do the 200ms sleep to resync.
  5. How much time does the UART transfer take? If it's longer than the time between lepton frames, this will cause problems with maintaining sync on subsequent transfers. In the PT1 firmware, the lepton DMA transfer goes on while we do other work in the main loop (remember, it's asynchronous); a transfer is always in flight. We signal the main loop that a new buffer is available when the DMA complete callback happens.

You might do well eliminating the UART transfer as a variable while you get the download working. Just print out the last line number and frame rate or something like that. Then you can work on getting it to work along with the UART transfer.