Use DMA for LEPTON 1 and 3.

This commit is contained in:
iabdalkader 2018-10-09 23:07:38 +02:00
parent 6df8ab7187
commit 4c554e2147

View File

@ -8,11 +8,14 @@
*/ */
#include STM32_HAL_H #include STM32_HAL_H
#include "mp.h"
#include "irq.h"
#include "cambus.h" #include "cambus.h"
#include "sensor.h" #include "sensor.h"
#include "systick.h" #include "systick.h"
#include "framebuffer.h" #include "framebuffer.h"
#include "omv_boardconfig.h" #include "omv_boardconfig.h"
#include "common.h"
#if defined(OMV_ENABLE_LEPTON) #if defined(OMV_ENABLE_LEPTON)
#include "crc16.h" #include "crc16.h"
@ -26,7 +29,16 @@
#define VOSPI_LINE_PIXELS (80) #define VOSPI_LINE_PIXELS (80)
#define VOSPI_NUMBER_PACKETS (60) #define VOSPI_NUMBER_PACKETS (60)
#define VOSPI_SPECIAL_LINE (20) #define VOSPI_SPECIAL_PACKET (20)
#define VOSPI_LINE_SIZE (80 * 2)
#define VOSPI_HEADER_SIZE (4)
#define VOSPI_PACKET_SIZE (VOSPI_HEADER_SIZE + VOSPI_LINE_SIZE)
#define VOSPI_HEADER_SEG(buf) (((buf[0] >> 4) & 0x7))
#define VOSPI_HEADER_PID(buf) (((buf[0] << 8) | (buf[1] << 0)) & 0x0FFF)
#define VOSPI_HEADER_CRC(buf) (((buf[2] << 8) | (buf[3] << 0)))
#define VOSPI_FIRST_PACKET (0)
#define VOSPI_FIRST_SEGMENT (1)
#define LEPTON_TIMEOUT (1000)
static int h_res = 0; static int h_res = 0;
static int v_res = 0; static int v_res = 0;
@ -34,134 +46,54 @@ static bool h_mirror = false;
static bool v_flip = false; static bool v_flip = false;
static SPI_HandleTypeDef SPIHandle; static SPI_HandleTypeDef SPIHandle;
static LEP_CAMERA_PORT_DESC_T handle; static DMA_HandleTypeDef DMAHandle;
extern uint8_t _line_buf;
extern uint8_t _vospi_buf;
extern const uint16_t rainbow_table[256]; extern const uint16_t rainbow_table[256];
static int reset(sensor_t *sensor) static bool vospi_resync = true;
static uint8_t *vospi_packet = &_line_buf;
static uint8_t *vospi_buffer = &_vospi_buf;
static volatile uint32_t vospi_pid = 0;
static volatile uint32_t vospi_seg = 1;
static uint32_t vospi_packets = 60;
void SPI3_IRQHandler(void)
{ {
memset(&handle, 0, sizeof(handle)); HAL_SPI_IRQHandler(&SPIHandle);
}
h_res = 0; void DMA1_Stream0_IRQHandler(void)
v_res = 0; {
h_mirror = false; HAL_DMA_IRQHandler(SPIHandle.hdmarx);
v_flip = false; }
DCMI_PWDN_LOW(); static void lepton_sync()
systick_sleep(10); {
HAL_SPI_Abort(&SPIHandle);
DCMI_PWDN_HIGH(); // Disable DMA IRQ
systick_sleep(10); HAL_NVIC_DisableIRQ(DMA1_Stream0_IRQn);
DCMI_RESET_LOW(); debug_printf("resync...\n");
systick_sleep(10); systick_sleep(200);
DCMI_RESET_HIGH(); vospi_resync = false;
systick_sleep(1000); vospi_pid = VOSPI_FIRST_PACKET;
vospi_seg = VOSPI_FIRST_SEGMENT;
LEP_CAMERA_PORT_DESC_T tmp_handle; HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
HAL_SPI_Receive_DMA(&SPIHandle, vospi_packet, VOSPI_PACKET_SIZE);
}
bool okay = false; static uint16_t lepton_calc_crc(uint8_t *buf)
{
for (int i = 0; i < 1000; i++) { buf[0] &= 0x0F;
LEP_RESULT result = LEP_OpenPort(0, LEP_CCI_TWI, 0, &tmp_handle); buf[1] &= 0xFF;
buf[2] = 0;
if (result == LEP_OK) { buf[3] = 0;
okay = true; return CalcCRC16Bytes(VOSPI_LINE_SIZE, (char *) buf);
break;
} else {
systick_sleep(1);
}
}
if (!okay) {
return -1;
}
bool booted = false;
for (int i = 0; i < 1000; i++) {
LEP_SDK_BOOT_STATUS_E status;
if (LEP_GetCameraBootStatus(&tmp_handle, &status) != LEP_OK) {
return -1;
}
if (status == LEP_BOOT_STATUS_BOOTED) {
booted = true;
break;
} else {
systick_sleep(1);
}
}
if (!booted) {
return -1;
}
bool busy = true;
for (int i = 0; i < 1000; i++) {
LEP_UINT16 status;
if (LEP_DirectReadRegister(&tmp_handle, LEP_I2C_STATUS_REG, &status) != LEP_OK) {
return -1;
}
if (!(status & LEP_I2C_STATUS_BUSY_BIT_MASK)) {
busy = false;
break;
} else {
systick_sleep(1);
}
}
if (busy) {
return -1;
}
busy = true;
for (int i = 0; i < 5000; i++) {
LEP_SYS_STATUS_E status;
if (LEP_GetSysFFCStatus(&tmp_handle, &status) != LEP_OK) {
return -1;
}
if (status == LEP_SYS_STATUS_READY) {
busy = false;
break;
} else {
systick_sleep(1);
}
}
if (busy) {
return -1;
}
if (LEP_SetRadEnableState(&tmp_handle, LEP_RAD_DISABLE) != LEP_OK) {
return -1;
}
LEP_AGC_ROI_T roi;
if (LEP_GetAgcROI(&tmp_handle, &roi) != LEP_OK) {
return -1;
}
int tmp_h_res = roi.endCol + 1;
int tmp_v_res = roi.endRow + 1;
if (LEP_SetAgcEnableState(&tmp_handle, LEP_AGC_ENABLE) != LEP_OK) {
return -1;
}
if (LEP_SetAgcCalcEnableState(&tmp_handle, LEP_AGC_ENABLE) != LEP_OK) {
return -1;
}
handle = tmp_handle;
h_res = tmp_h_res;
v_res = tmp_v_res;
return 0;
} }
static int sleep(sensor_t *sensor, int enable) static int sleep(sensor_t *sensor, int enable)
@ -288,157 +220,192 @@ static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef)
return 0; return 0;
} }
static int reset(sensor_t *sensor)
{
DCMI_PWDN_LOW();
systick_sleep(10);
DCMI_PWDN_HIGH();
systick_sleep(10);
DCMI_RESET_LOW();
systick_sleep(10);
DCMI_RESET_HIGH();
systick_sleep(1000);
LEP_AGC_ROI_T roi;
LEP_CAMERA_PORT_DESC_T handle = {0};
h_res = v_res = h_mirror = v_flip = 0;
for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) {
if (LEP_OpenPort(0, LEP_CCI_TWI, 0, &handle) == LEP_OK) {
break;
}
if (HAL_GetTick() - start >= LEPTON_TIMEOUT) {
return -1;
}
}
for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) {
LEP_SDK_BOOT_STATUS_E status;
if (LEP_GetCameraBootStatus(&handle, &status) != LEP_OK) {
return -1;
}
if (status == LEP_BOOT_STATUS_BOOTED) {
break;
}
if (HAL_GetTick() - start >= LEPTON_TIMEOUT) {
return -1;
}
}
for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) {
LEP_UINT16 status;
if (LEP_DirectReadRegister(&handle, LEP_I2C_STATUS_REG, &status) != LEP_OK) {
return -1;
}
if (!(status & LEP_I2C_STATUS_BUSY_BIT_MASK)) {
break;
}
if (HAL_GetTick() - start >= LEPTON_TIMEOUT) {
return -1;
}
}
for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) {
LEP_SYS_STATUS_E status;
if (LEP_GetSysFFCStatus(&handle, &status) != LEP_OK) {
return -1;
}
if (status == LEP_SYS_STATUS_READY) {
break;
}
if (HAL_GetTick() - start >= (LEPTON_TIMEOUT * 5)) {
return -1;
}
}
if (LEP_SetRadEnableState(&handle, LEP_RAD_DISABLE) != LEP_OK
|| LEP_GetAgcROI(&handle, &roi) != LEP_OK
|| LEP_SetAgcEnableState(&handle, LEP_AGC_ENABLE) != LEP_OK
|| LEP_SetAgcCalcEnableState(&handle, LEP_AGC_ENABLE) != LEP_OK) {
return -1;
}
h_res = roi.endCol + 1;
v_res = roi.endRow + 1;
if (v_res > 60) {
vospi_packets = 240;
} else {
vospi_packets = 60;
}
// resync and enable DMA before the first snapshot.
vospi_resync = true;
return 0;
}
#define HAL_CLEANINVALIDATE_DCACHE(addr, size) \
(SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \
((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
(void) lepton_calc_crc; // to shut the compiler up.
if (vospi_resync == true) {
return; // nothing to do here
}
// Invalidate cache prior to access by CPU
HAL_CLEANINVALIDATE_DCACHE(vospi_packet, VOSPI_PACKET_SIZE);
if (vospi_pid < vospi_packets && (vospi_packet[0] & 0xF) != 0xF) {
uint32_t pid = VOSPI_HEADER_PID(vospi_packet);
uint32_t seg = VOSPI_HEADER_SEG(vospi_packet);
if (pid != (vospi_pid % VOSPI_NUMBER_PACKETS)) {
if (vospi_pid == VOSPI_FIRST_PACKET) {
// Wait for the first packet of the first segement.
vospi_pid = VOSPI_FIRST_PACKET;
vospi_seg = VOSPI_FIRST_SEGMENT;
} else { // lost sync
vospi_resync = true;
debug_printf("lost sync, packet id:%lu expected id:%lu \n", pid, vospi_pid);
}
} else if (vospi_packets > 60 && pid == VOSPI_SPECIAL_PACKET && seg != vospi_seg ) {
if (vospi_seg == VOSPI_FIRST_SEGMENT) {
// Wait for the first packet of the first segement.
vospi_pid = VOSPI_FIRST_PACKET;
vospi_seg = VOSPI_FIRST_SEGMENT;
} else { // lost sync
vospi_resync = true;
debug_printf("lost sync, segment id:%lu expected id:%lu\n", seg, vospi_seg);
}
} else {
memcpy(vospi_buffer + vospi_pid * VOSPI_LINE_SIZE,
vospi_packet + VOSPI_HEADER_SIZE, VOSPI_LINE_SIZE);
if ((++vospi_pid % VOSPI_NUMBER_PACKETS) == 0) {
vospi_seg++;
}
}
}
}
static int snapshot(sensor_t *sensor, image_t *image, streaming_cb_t cb) static int snapshot(sensor_t *sensor, image_t *image, streaming_cb_t cb)
{ {
fb_update_jpeg_buffer();
if ((!h_res) || (!v_res) || (!sensor->framesize) || (!sensor->pixformat)) { if ((!h_res) || (!v_res) || (!sensor->framesize) || (!sensor->pixformat)) {
return -1; return -1;
} }
int y_scaler = h_res / VOSPI_LINE_PIXELS; fb_update_jpeg_buffer();
int vospi_line_size = sizeof(uint16_t) + sizeof(uint16_t) + (VOSPI_LINE_PIXELS * sizeof(uint16_t));
uint8_t buffer[vospi_line_size];
bool reset = false; vospi_pid = VOSPI_FIRST_PACKET;
uint32_t time = systick_current_millis(); vospi_seg = VOSPI_FIRST_SEGMENT;
for (int y = 0; y < v_res;) { do {
for (int x = 0; x < h_res;) { if (vospi_resync == true) {
if (sys_tick_has_passed(time, (h_res > VOSPI_LINE_PIXELS) ? 3000 : 1000)) { lepton_sync();
return -1;
}
int state = __get_PRIMASK();
__disable_irq();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
HAL_StatusTypeDef status = HAL_SPI_Receive(&SPIHandle, buffer, vospi_line_size, 1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
__set_PRIMASK(state);
if (status != HAL_OK) {
return -1;
}
if ((buffer[0] & 0xF) == 0xF) {
continue;
}
int ttt = (buffer[0] >> 4) & 0x7;
int packet_num = ((buffer[0] << 8) | (buffer[1] << 0)) & 0xFFF;
int crc = (buffer[2] << 8) | (buffer[3] << 0);
buffer[0] &= 0x0F;
buffer[1] &= 0xFF;
buffer[2] = 0;
buffer[3] = 0;
if (CalcCRC16Bytes(vospi_line_size, (char *) buffer) != crc) {
systick_sleep(200);
y = x = 0;
reset = false;
continue;
}
if ((y == 0) && (x == 0) && (packet_num != 0)) {
systick_sleep(200);
y = x = 0;
reset = false;
continue;
}
if ((((y % (VOSPI_NUMBER_PACKETS / y_scaler)) * y_scaler) + (x / VOSPI_LINE_PIXELS)) != packet_num) {
systick_sleep(200);
y = x = 0;
reset = false;
continue;
}
if ((h_res > VOSPI_LINE_PIXELS)
&& (packet_num == VOSPI_SPECIAL_LINE)
&& (((y / (VOSPI_NUMBER_PACKETS / y_scaler)) + 1) != ttt)) {
if (!ttt) {
reset = true;
} else {
systick_sleep(200);
y = x = 0;
reset = false;
continue;
}
}
image_t img;
img.w = MAIN_FB()->u;
img.h = MAIN_FB()->v;
img.bpp = MAIN_FB()->bpp; // invalid
img.data = MAIN_FB()->pixels; // valid
float x_scale = resolution[sensor->framesize][0] / ((float) h_res);
float y_scale = resolution[sensor->framesize][1] / ((float) v_res);
// MAX == KeepAspectRationByExpanding - MIN == KeepAspectRatio
float scale = IM_MAX(x_scale, y_scale);
int x_offset = (resolution[sensor->framesize][0] - (h_res * scale)) / 2;
int y_offset = (resolution[sensor->framesize][1] - (v_res * scale)) / 2;
// The code below upscales the source image to the requested frame size
// and then crops it to the window set by the user.
for (int yyy = fast_floorf(y * scale) + y_offset,
yyyy = fast_ceilf((y + 1) * scale) + y_offset; yyy < yyyy; yyy++) {
if ((MAIN_FB()->y <= yyy) && (yyy < (MAIN_FB()->y + MAIN_FB()->v))) {
for (int xxx = fast_floorf(x * scale) + x_offset,
xxxx = fast_ceilf((x + VOSPI_LINE_PIXELS) * scale) + x_offset; xxx < xxxx; xxx++) {
if ((MAIN_FB()->x <= xxx) && (xxx < (MAIN_FB()->x + MAIN_FB()->u))) {
int i = (xxx / scale) - x;
// Value is the 14-bit value from the FLIR IR camera.
// However, with AGC enabled only the bottom 8-bits are non-zero.
int value = ((buffer[(i*2)+4] << 8) | (buffer[(i*2)+5] << 0)) & 0x3FFF;
int t_x = xxx - MAIN_FB()->x;
int t_y = yyy - MAIN_FB()->y;
if (h_mirror) t_x = MAIN_FB()->u - t_x - 1;
if (v_flip) t_y = MAIN_FB()->v - t_y - 1;
switch (sensor->pixformat) {
case PIXFORMAT_RGB565: {
IMAGE_PUT_RGB565_PIXEL(&img, t_x, t_y, rainbow_table[value & 0xFF]);
break;
}
case PIXFORMAT_GRAYSCALE: {
IMAGE_PUT_GRAYSCALE_PIXEL(&img, t_x, t_y, value & 0xFF);
break;
}
default: {
break;
}
}
}
}
}
}
x += VOSPI_LINE_PIXELS;
} }
__WFI();
} while (vospi_pid < vospi_packets);
y += 1; image->w = MAIN_FB()->w;
image->h = MAIN_FB()->h;
image->bpp = MAIN_FB()->bpp; // invalid
image->data = MAIN_FB()->pixels; // valid
if (reset && (!(y % (VOSPI_NUMBER_PACKETS / y_scaler)))) { uint16_t *src = (uint16_t*) vospi_buffer;
y -= VOSPI_NUMBER_PACKETS / y_scaler;
reset = false; for (int y=0; y<v_res; y++) {
for (int x=0; x<h_res; x++) {
// Value is the 14-bit value from the FLIR IR camera.
// However, with AGC enabled only the bottom 8-bits are non-zero.
uint8_t val = src[y*h_res+x]>>8;
switch (sensor->pixformat) {
case PIXFORMAT_RGB565: {
IMAGE_PUT_RGB565_PIXEL(image, x, y, rainbow_table[val]);
break;
}
case PIXFORMAT_GRAYSCALE: {
IMAGE_PUT_GRAYSCALE_PIXEL(image, x, y, val);
break;
}
default: {
break;
}
}
} }
} }
MAIN_FB()->w = MAIN_FB()->u;
MAIN_FB()->h = MAIN_FB()->v;
switch (sensor->pixformat) { switch (sensor->pixformat) {
case PIXFORMAT_RGB565: { case PIXFORMAT_GRAYSCALE: {
MAIN_FB()->bpp = sizeof(uint16_t); MAIN_FB()->bpp = 1;
break; break;
} }
case PIXFORMAT_GRAYSCALE: { case PIXFORMAT_RGB565: {
MAIN_FB()->bpp = sizeof(uint8_t); MAIN_FB()->bpp = 2;
break; break;
} }
default: { default: {
@ -446,69 +413,12 @@ static int snapshot(sensor_t *sensor, image_t *image, streaming_cb_t cb)
} }
} }
image->w = MAIN_FB()->w; image->bpp = MAIN_FB()->bpp;
image->h = MAIN_FB()->h;
image->bpp = MAIN_FB()->bpp;
image->data = MAIN_FB()->pixels;
return 0; return 0;
} }
int lepton_init(sensor_t *sensor) int lepton_init(sensor_t *sensor)
{ {
memset(&SPIHandle, 0, sizeof(SPIHandle));
SPIHandle.Instance = SPI3;
SPIHandle.Init.NSS = SPI_NSS_SOFT;
SPIHandle.Init.Mode = SPI_MODE_MASTER;
SPIHandle.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
SPIHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SPIHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
SPIHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
SPIHandle.Init.BaudRatePrescaler = LEPTON_SPI_PRESCALER;
__HAL_RCC_SPI3_CLK_ENABLE();
if (HAL_SPI_Init(&SPIHandle) != HAL_OK) {
__HAL_RCC_SPI3_FORCE_RESET();
__HAL_RCC_SPI3_RELEASE_RESET();
__HAL_RCC_SPI3_CLK_DISABLE();
return -1;
}
GPIO_InitTypeDef GPIO_InitTypeDefSS;
GPIO_InitTypeDefSS.Pin = GPIO_PIN_15;
GPIO_InitTypeDefSS.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitTypeDefSS.Pull = GPIO_PULLUP;
GPIO_InitTypeDefSS.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitTypeDefSS.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOA, &GPIO_InitTypeDefSS);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
GPIO_InitTypeDef GPIO_InitTypeDefSCLK;
GPIO_InitTypeDefSCLK.Pin = GPIO_PIN_3;
GPIO_InitTypeDefSCLK.Mode = GPIO_MODE_AF_PP;
GPIO_InitTypeDefSCLK.Pull = GPIO_PULLUP;
GPIO_InitTypeDefSCLK.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitTypeDefSCLK.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOB, &GPIO_InitTypeDefSCLK);
GPIO_InitTypeDef GPIO_InitTypeDefMISO;
GPIO_InitTypeDefMISO.Pin = GPIO_PIN_4;
GPIO_InitTypeDefMISO.Mode = GPIO_MODE_AF_PP;
GPIO_InitTypeDefMISO.Pull = GPIO_PULLUP;
GPIO_InitTypeDefMISO.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitTypeDefMISO.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOB, &GPIO_InitTypeDefMISO);
GPIO_InitTypeDef GPIO_InitTypeDefMOSI;
GPIO_InitTypeDefMOSI.Pin = GPIO_PIN_5;
GPIO_InitTypeDefMOSI.Mode = GPIO_MODE_AF_PP;
GPIO_InitTypeDefMOSI.Pull = GPIO_PULLUP;
GPIO_InitTypeDefMOSI.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitTypeDefMOSI.Alternate = GPIO_AF7_SPI3;
HAL_GPIO_Init(GPIOB, &GPIO_InitTypeDefMOSI);
sensor->gs_bpp = sizeof(uint8_t); sensor->gs_bpp = sizeof(uint8_t);
sensor->reset = reset; sensor->reset = reset;
sensor->sleep = sleep; sensor->sleep = sleep;
@ -541,6 +451,85 @@ int lepton_init(sensor_t *sensor)
SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0);
SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0);
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Pull = GPIO_PULLUP;
GPIO_Init.Mode = GPIO_MODE_AF_PP;
GPIO_Init.Alternate = GPIO_AF6_SPI3;
GPIO_Init.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_Init.Pin = GPIO_PIN_3;
HAL_GPIO_Init(GPIOB, &GPIO_Init);
GPIO_Init.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOB, &GPIO_Init);
GPIO_Init.Pin = GPIO_PIN_5;
HAL_GPIO_Init(GPIOB, &GPIO_Init);
GPIO_Init.Pin = GPIO_PIN_15;
HAL_GPIO_Init(GPIOA, &GPIO_Init);
// Configure the DMA handler for Transmission process
DMAHandle.Instance = DMA1_Stream0;
DMAHandle.Init.Request = DMA_REQUEST_SPI3_RX;
DMAHandle.Init.Mode = DMA_CIRCULAR;
DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;
DMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
// When the DMA is configured in direct mode (the FIFO is disabled), the source and
// destination transfer widths are equal, and both defined by PSIZE (MSIZE is ignored).
// Additionally, the burst transfers are not possible (MBURST and PBURST are ignored).
DMAHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
DMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
// Note MBURST and PBURST are ignored.
DMAHandle.Init.MemBurst = DMA_MBURST_INC4;
DMAHandle.Init.PeriphBurst = DMA_PBURST_INC4;
DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DMAHandle.Init.MemInc = DMA_MINC_ENABLE;
DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;
// NVIC configuration for DMA transfer complete interrupt
NVIC_SetPriority(DMA1_Stream0_IRQn, IRQ_PRI_DMA21);
HAL_NVIC_DisableIRQ(DMA1_Stream0_IRQn);
HAL_DMA_DeInit(&DMAHandle);
if (HAL_DMA_Init(&DMAHandle) != HAL_OK) {
// Initialization Error
return -1;
}
memset(&SPIHandle, 0, sizeof(SPIHandle));
SPIHandle.Instance = SPI3;
SPIHandle.Init.NSS = SPI_NSS_HARD_OUTPUT;
SPIHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
SPIHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
SPIHandle.Init.Mode = SPI_MODE_MASTER;
SPIHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SPIHandle.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
SPIHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SPIHandle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA;
SPIHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SPIHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
SPIHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
SPIHandle.Init.BaudRatePrescaler = LEPTON_SPI_PRESCALER;
// Recommanded setting to avoid glitches
SPIHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
__HAL_RCC_SPI3_CLK_ENABLE();
if (HAL_SPI_Init(&SPIHandle) != HAL_OK) {
__HAL_RCC_SPI3_FORCE_RESET();
__HAL_RCC_SPI3_RELEASE_RESET();
__HAL_RCC_SPI3_CLK_DISABLE();
return -1;
}
// Associate the initialized DMA handle to the the SPI handle
__HAL_LINKDMA(&SPIHandle, hdmarx, DMAHandle);
// NVIC configuration for SPI transfer complete interrupt
NVIC_SetPriority(SPI3_IRQn, IRQ_PRI_DCMI);
HAL_NVIC_EnableIRQ(SPI3_IRQn);
return 0; return 0;
} }
#else #else