I connected my Flir Lepton Camera to my board, and I'm trying to have a continuous stream of the image, thanks to the program ThermalView (source code here: https://github.com/groupgets/LeptonModule/tree/master/software/ThermalView)
I compiled and downloaded the following code on my board:
int main(void)
{
//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();
SystemClock_Config();
leptonEnd();
// LEPTON VDD OFF
HAL_Delay(1000);
// LEPTON VDD ON
HAL_Delay(185);
LeptonConfigure_I2C();
while(1)
{
LeptonReadFrame();
frameToPc();
}
}
// Output image buffer to USART2
void frameToPc()
{
static uint8_t frameSkipper = 0;
uint8_t timeStamp = (HAL_GetTick() - last_frame_millis); // calculate time passed since last been here
last_frame_millis = HAL_GetTick();
if(frameSkipper==4)
{
//PSEDO//
//IMGtoRGB();
////////
uint8_t thermalView_header[] = {0xDE,0xAD,0xBE,0xEF}; // 4-byte header for ThermalView application
HAL_Delay(1000);
HAL_UART_Transmit_DMA(&huart2, &thermalView_header[0], 4); // print header
while(huart2.gState != HAL_UART_STATE_READY); // wait for transmission to complete
HAL_UART_Transmit_DMA(&huart2, &IMG[0], LEPTON_IMG_SIZE_BYTES);
frameSkipper = 0;
}
frameSkipper++;
}uint8_t LeptonReadFrame()
{
uint8_t i, frame_number, frame_complete=0;
uint16_t bad_frame_counter=0;
while(!frame_complete)
{
leptonBegin();
HAL_SPI_Receive(&hspi1, &FramePacket[0], LEPTON_PACKET_LENGTH, 1000); // READ LINE
leptonEnd();
//HAL_UART_Transmit(&huart2, &FramePacket[0], LEPTON_PACKET_LENGTH, 1000); // PRINT LINE
if( (FramePacket[0] & 0x0f) != 0x0f ) // not discard frame
{
frame_number = FramePacket[1];
if(frame_number < 60) // valid frame
{
bad_frame_counter = 0;
for(i= 0; i<LEPTON_PACKET_CONTENT_LENGTH; i++)
{
IMG[frame_number*LEPTON_PACKET_CONTENT_LENGTH+i] = FramePacket[i+4]; // copy line into IMG buffer, ignoring ID and CRC
}
}
else
{
bad_frame_counter++;
}
if(frame_number == 59)
{
frame_complete = 1;
}
if(bad_frame_counter>1000) // 800 lines = 5 bad frames = resync needed
{
bad_frame_counter = 0;
HAL_Delay(185); // CS is already disabled so the delay is enougth
}
}
}
return 1;
}
I'm succesfully getting a stream, but I have to put a delay of 1 sec between each frame, and have to skip frames between 2 frames I'm sending to the computer. If you pay attention to something wrong in the code which prevents increasing the frame rate, let me know.
Are you using a Lepton 2 or Lepton 3? The Lepton 3 will require acquisition of not only the "Frames" but also 4 "segments" There are also 2 blank screens output by the Lepton Modules. More details in this document:
http://www.flir.com/uploadedFiles/OEM/Products/LWIR-Cameras/Lepton/Lepton-vs-Lepton-3-App-Note.pdf
comparing the Lepton 2X series (80x60) resolution and the Lepton 3 (160x120) resolution.
The four most significant differences between the Lepton and Lepton 3 VoSPI interfaces are:
1) On Lepton, reconstructing a video frame from the individual packets requires the host to decode the packet number from each packet header. On Lepton 3, the host must decode both the packet number and the segment number.
2) The total number of bits per frame is 4X greater for Lepton 3 than for Lepton. Consequently, the minimum SPI clock rate is 4X faster. The maximum SPI clock rate for both modules is 20 MHz.
3) Both Lepton and Lepton 3 provide the option to output a sync pulse on GPIO3. The frequency of the pulse is 4X higher on Lepton 3 than on Lepton. For Lepton 3, the sync pulse represents when the next available segment is available whereas for Lepton it indicates when the next available frame is available.
4) When telemetry is enabled in Lepton, it results in three extra video lines (63 total packets per frame). When telemetry is enabled in Lepton 3, it results in 1 additional packet per segment for a total of 2 extra video lines.
Im trying to get the lepton 3 to work on my stm32f746g-discovery board.
Related
First time working with DMA here and I'm getting data loss when the frequency of a PWM signal is varied during the DMA reading. The DMA request is triggered by a 16MHz clock. I'm using DMA2 on STM32f429zi.
The DMA direction is peripheral to memory, where I try to read the whole GPIO port E to memory. The data loss is clearly visible in the beginning of the DMA reading when the PWM frequency is changed. If I comment out the code with the varying of PWM frequency (see part of the code below), there is no visible data loss in the DMA reading.
You can see in the attached image that the upper plot loses data points of the sine wave (4 points per period) and in the lower plot there is no data loss.
As I understand, DMA should work independently and not be affected by CPU, but for me it seems to not be the case. Could this be due to working with a too high clock frequency? Or am I missing something else? I'm really stuck on this problem, any help is appreciated.
Regards,
Linda
/*------------------- Comment out when not changing PWM frequency --------------------------------------------------------------------*/
// /* Start 40 MHz */
// TIM3->CCR1 = 1; // 40 MHz
/*------------------------------------------------------------------------------------------------------------------------------------*/
/* Start DMA for ping signal with length BUFFER_SIZE (PA9 (channel 2) is clockout+ of ADC, sampling on falling edge of PA9) */
if (HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC2], (uint32_t)&(GPIOF->IDR), (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
/* Transfer Error */
Error_Handler();
}
/*------------------- Comment out when not changing PWM frequency --------------------------------------------------------------------*/
// /* Continue while timer is lower than 1,3 us */
// while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 13)
// {
// }
// /* Start ping, 4 MHz */
// TIM3->ARR = 20; // period
// TIM3->CCR1 = 9; // pulse
// timer_val1 = __HAL_TIM_GET_COUNTER(&htim5);
// while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 9) // 5 pulses
// {
// }
//
// TIM3->ARR = 1; // 40Mhz
// TIM3->CCR1 = 1;
// while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 25)
// {
// }
/*------------------------------------------------------------------------------------------------------------------------------------*/
I am working on using Raspberry Pi to generate hardware PWM to control my stepper motors. When I tried hardware pwm, I found that I can not control the pulse in numbers such as I just wanted motor to move 8000 steps and then stop.
I don't want use time to turn off the PWM, I want specific steps.
#include <bcm2835.h>
#include <stdio.h>
// PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18)
// in alt fun 5.
// Note that this is the _only_ PWM pin available on the RPi IO headers
#define PIN RPI_GPIO_P1_12
// and it is controlled by PWM channel 0
#define PWM_CHANNEL 0
// This controls the max range of the PWM signal
#define RANGE 1024
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
// Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);
// Clock divider is set to 16.
// With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
// the pulse repetition frequency will be
// 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); //CTL reg
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); //RNG1/2 reg
// Vary the PWM m/s ratio between 1/RANGE and (RANGE-1)/RANGE
int direction = 1;
int data = 1;
while (1)
{
if (data == 1)
direction = 1;
else if (data == RANGE-1)
direction = -1;
data += direction;
bcm2835_pwm_set_data(PWM_CHANNEL, data);
bcm2835_delay(1);
}
bcm2835_close();
return 0;
}
Can this code achieve my thought (modifying some registers of pwm)? Which reg of PWM control the autofill(autopadding), I just want to know how to stop sending pulses after stopping the motor.
I'm trying to set communication between esp32 (master) and stm32 (slave) over SPI. esp32 is running under micropython and sends four bytes, for example
spi.write_readinto(b'\x31\x32\x33\x34', buf)
stm32' code is here (instead of this i use SPI_InitDef.SPI_NSS = SPI_NSS_Soft;)
void SPI_Init(void) {
...
// initialize SPI slave
// for slave, no need to define SPI_BaudRatePrescaler
SPI_InitDef.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitDef.SPI_Mode = SPI_Mode_Slave;
SPI_InitDef.SPI_DataSize = SPI_DataSize_8b; // 8-bit transactions
SPI_InitDef.SPI_FirstBit = SPI_FirstBit_MSB; // MSB first
SPI_InitDef.SPI_CPOL = SPI_CPOL_Low; // CPOL = 0, clock idle low
SPI_InitDef.SPI_CPHA = SPI_CPHA_2Edge; // CPHA = 1
SPI_InitDef.SPI_NSS = SPI_NSS_Hard; // use hardware SS
SPI_InitDef.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // APB2 72/64 = 1.125 MHz
SPI_InitDef.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitDef);
SPI_Cmd(SPI1, ENABLE);
NVIC_EnableIRQ(SPI1_IRQn);
//Тут мы разрешаем прерывание по приему
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
}
void main() {
/* Setup SysTick Timer for 10ms interrupts */
if (SysTick_Config(SystemCoreClock / 100))
{
/* Capture error */
while (1);
}
/* Configure the SysTick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x0);
SPI_Init();
while(1) {
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
for (u8 i=0; i<4; i++) {
printf("0x%02x ", SPI_I2S_ReceiveData(SPI1));
}
printf("\r\n");
}
}
But when I send four bytes 0x31 0x32 0x33 0x34 (analyzer confirms bytes were sent) and my stm gets only 0x31 0x32 0x31 0x32
UPD
I use std periph library and SPI_I2S_ReceiveData is a native method to read byte from SPI.
uint16_t SPI_I2S_ReceiveData ( SPI_TypeDef * SPIx )
Returns the most recent received data by the SPIx/I2Sx peripheral.
Parameters:
SPIx,: To select the SPIx/I2Sx peripheral, where x can be: 1, 2 or 3 in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode.
Return values:
The value of the received data.
uint16_t SPI_I2S_ReceiveData ( SPI_TypeDef * SPIx )
Returns the most recent received data by the SPIx/I2Sx peripheral.
Parameters:
SPIx,: To select the SPIx/I2Sx peripheral, where x can be: 1, 2 or 3 in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode.
Return values:
The value of the received data.
But maybe I exit out from IRQ before all data are read. I found to run the while loop until the transmission of the last byte is complete
I think the following code is not correct (but I don't know what the function SPI_I2S_ReceiveData is doing):
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
for (u8 i=0; i<4; i++) {
printf("0x%02x ", SPI_I2S_ReceiveData(SPI1));
}
You exit from the while as soon as one byte is ready to be read. I assume SPI_I2S_ReceiveData is only reading the SPI FIFO. in that case you try to read 4 bytes when possibly only one or two has been received.
You didn't precise the kind of STM32 you're using so I am describing the SPI of STM32H7 (as far as I know it should be pretty similar in other STM32).
To setup a reception in slave mode you should define in particular these 3 parameters:
the length of the socalled "frame" (number of bytes to be read/written at once). This is the field SPI_DataSize` in the HAL data structure, here 8 bits.
the number of transfer (TSIZE) which specifies when the End Of Transmission event is generated. It is expressed in number of "frames". This parameter must be set through register SPI.CR2 before each reception (provided you know the number of bytes to be received of course).
the "FIFO threshold". It specifies at which frequency an event RXP or TXP is generated. You can change this parameter to decrease the workload on the software but to receive only 4 bytes it has no impact.
In your case I think you should setup a transfer size of 4 (4 bytes) and wait for EOT flag to be set. When it is set you only have to read 4 bytes from SPI Receive Register (you can read all 4 bytes at once by the way).
I suggest you do not use the HAL but write your own SPI reception / transmission routines by reading / writing registers. It is not a very complex peripheral (so it will not cost you a lot of time) and you will understand precisely how it works (instead of digging into the HAL).
I'm trying to develop a interface SPI and I have started with a simple configuration.
The question is that SCK seems to work fine but MOSI doesnt works.
Here is my code and my test logical tester.
#include <stdlib.h>
#include <plib.h>
// example functions prototypes
int SpiDoMasterSlaveExample(int nCycles);
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster);
// some definitions
#define MIN_SPI_TXFER_SIZE 8 // min number of words per transfer
#define MAX_SPI_TXFER_SIZE 512 // max number of words per transfer
// configuration settings
#pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
int main(void)
{
SYSTEMConfigPerformance(72000000L);
srand(ReadCoreTimer()); // seed the pseudo random generator
if(!SpiDoMasterSlaveExample(100))
{
return 0; // our example failed
}
return 1;
}
int SpiDoMasterSlaveExample(int nCycles)
{
int fail=0; // overall result
SpiInitDevice(1, 1, 1, 1); // initialize the SPI channel 1 as master, frame master
SpiInitDevice(2, 0, 1, 0); // initialize the SPI channel 2 as slave, frame slave
while(nCycles-- && !fail)
{
unsigned int txferSize;
unsigned short* pTxBuff;
unsigned short* pRxBuff;
txferSize=MIN_SPI_TXFER_SIZE+rand()%(MAX_SPI_TXFER_SIZE-MIN_SPI_TXFER_SIZE+1); // get a random transfer size
pTxBuff=(unsigned short*)malloc(txferSize*sizeof(short));
pRxBuff=(unsigned short*)malloc(txferSize*sizeof(short)); // we'll transfer 16 bits words
if(pTxBuff && pRxBuff)
{
unsigned short* pSrc=pTxBuff;
unsigned short* pDst=pRxBuff;
int ix;
int rdData;
for(ix=0; ix<txferSize; ix++)
{
pTxBuff[ix]='A'; // fill buffer with some random data
}
ix=txferSize+1; // transfer one extra word to give the slave the possibility to reply back the last sent word
while(ix--)
{
SpiChnPutC(1, *pSrc++); // send data on the master channel, SPI1
rdData=SpiChnGetC(1); // get the received data
if(ix!=txferSize)
{ // skip the first received character, it's garbage
*pDst++=rdData; // store the received data
}
rdData=SpiChnGetC(2); // receive data on the slave channel, SPI2
SpiChnPutC(2, rdData); // relay back data
}
// now let's check that the data was received ok
pSrc=pTxBuff;
pDst=pRxBuff;
for(ix=0; ix<txferSize; ix++)
{
if(*pDst++!=*pSrc++)
{
fail=1; // data mismatch
break;
}
}
}
else
{ // memory allocation failed
fail=1;
}
free(pRxBuff);
free(pTxBuff); // free the allocated buffers
}
return !fail;
}
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster)
{
unsigned int config=SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word
if(isMaster)
{
config|=SPI_CON_MSTEN;
}
if(frmEn)
{
config|=SPI_CON_FRMEN;
if(!frmMaster)
{
config|=SPI_CON_FRMSYNC;
}
}
SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example
}
Sorry, I can't post the logical analyser image for my reputation points.
I'm trying to send "A" all time (fill buffer transmit). That's send data to SPI1.
I'm reading SPI1 from my Microchip Expansion Board I/O where SPI1 is in pins 41 and 43 (41 SCK and 43 SDO).
In SPI2, pin 23 and 25, obviously I have not any traffic.
Does anyone have idea of this error?
Thanks a lot
The PIC32MX series has mapable input and output pins for some peripherals, including the SPI. This means, that MOSI and MISO can be mapped to different pins, depending on your specific needs.
You need to specify this in code before you start using the SPI, otherwise, the PIC won't know which pins to use.
The following is just an example of how to setup the pins (peripheral pin select). You need to look in your PIC's datasheet for the mappings. The first parameter in the calls is the table index from the datasheet.
/* inputs */
PPSInput(2, SDI1, RPF2); // F2, MEMORY MISO -> SPI1SDI
PPSInput(2, SDI2, RPG7); // G7, ZB MISO -> SPI2SDI
/* outputs */
PPSOutput(4, RPF3, SDO1); // F3, MEMORY MOSI -> SPI1SDO
PPSOutput(1, RPG8, SDO2); // G8, ZB MOSI -> SPI2SDO
As described before, check your peripheral pin select. Additional you must set your port direction to Output (PDx-Register). MISO must be set to an Input.
The below IRQ handler drains the USART3 of incoming 32 byes of data. The first IRQ TC event reads the first 6 bytes, then reprograms the DMA engine to read in the last 24 bytes. The second TC repograms it to read the header again This method will allow for variable length messages using DMA. However I cannot seem to be able the change the DMA start address. I'd like to be able to store each message in a seperate buffer, however it just over writes the first buffer on upon recieving each message. What am I doing wrong? The microcontroller is a STM32F103ze (Cortex-M3).
void DMA1_Channel3_IRQHandler(void)
{
uint32_t tmpreg = 0;
/* Test on DMA1 Channel3 Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_IT_TC3))
{
if (rx3_dma_state == RECIEVE_HEADER )
{
DMA_Cmd(DMA1_Channel3, DISABLE);/* Disable DMA1_Channel2 transfer*/
// Now that have received the header. Configure the DMA engine to receive
// the data portion of the message
DMA_SetCurrDataCounter(DMA1_Channel3,26);
DMA_Cmd(DMA1_Channel3, ENABLE);
} else if ( rx3_dma_state == RECIEVE_MSG )
{
//CurrDataCounterEnd3 = DMA_GetCurrDataCounter(DMA1_Channel3);
DMA_Cmd(DMA1_Channel3, DISABLE);
/* Get Current Data Counter value after complete transfer */
USART3_Rx_DMA_Channel_Struct->CMAR = (uint32_t) RxBuffer3LookUp[rx_buffer_index];
DMA_SetCurrDataCounter(DMA1_Channel3, 6);
DMA_Cmd(DMA1_Channel3,ENABLE);
// Set up DMA to write into the next buffer slot (1 of 8)
++rx_buffer_index;
rx_buffer_index %= 8;
}
/* Clear DMA1 Channel6 Half Transfer, Transfer Complete and Global interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_GL3);
}
// Update the state to read fake header of 6 bytes
// or to read the fake data section of the message 26 bytes
++rx3_dma_state;
rx3_dma_state %= 2;
isr_sem_send(dma_usart3_rx_sem);
}
You say:
...reprograms the DMA engine to read in the last 24 bytes.
but your code says:
DMA_SetCurrDataCounter(DMA1_Channel3,26);
Is that right? Is it 24 or 26?