Menghubungkan Pencari Thermal Seek ke STM32

Hubungkan imager termal ke mikrokontroler? Tidak masalah! Terutama jika itu adalah STM32 dengan antarmuka USB Host dan Pencari Thermal Thermal dari Dadget!


Menyolder besi melalui mata Seager Thermal Thermal Imager

Pendahuluan


Saya pikir semua orang telah menemukan gadget seperti imager termal, yah, setidaknya baca tentang mereka. Dan di antara perangkat ini, ada seluruh subkelas gadget yang bukan perangkat independen, tetapi berfungsi sebagai semacam set-top box untuk komputer atau smartphone.

Hari ini kita akan berbicara tentang menghubungkan Seager Thermal imager ke mikrokontroler STM32. Dan perusahaan Dadget memberi saya perangkat ini. Pada hamparan Geektimes, pencitraan termal ini dianggap lebih dari sekali: mencakup sebagian besar kerjanya dengan Android, serta artikel tentang menghubungkan perangkat ini ke PC. Dalam ulasan saya, saya ingin berbicara tentang pengalaman saya sendiri menghubungkan Seager Thermal imager ke mikrokontroler STM32 melalui host USB.

Persyaratan perangkat keras


Tidak terlalu spesifik! Yang harus dimiliki STM32 Anda adalah antarmuka USB yang mampu bekerja dalam mode Host dan beberapa antarmuka untuk mengendalikan layar LCD. Pilihan yang paling jelas adalah dengan menggunakan STM32F4 - Discovery. Saya memiliki papan STM32F746G-Discovery di tangan. Dengan demikian, uraiannya akan untuk papan ini, tapi! Karena kode ini dibuat di lingkungan CubeMX, dimungkinkan untuk menggunakan EVM lain. Saya menganggap pembayaran yang saya lakukan berlebihan untuk proyek ini.

Bagian perangkat lunak


Imager termal ini tidak menerapkan kelas apa pun saat berkomunikasi melalui USB. Semua interaksi dilakukan secara langsung, permintaan massal melalui titik akhir. Dengan mengirimkan perintah (permintaan) ke titik akhir kontrol, Anda dapat mengaktifkan imager termal, mengkalibrasi, dan membuatnya mengirimkan frame, atau beberapa frame. Pekerjaan terinci dengan Seek Thermal dijelaskan di forum ini.

Dengan demikian, agar imager termal bekerja dengan mikrokontroler STM32, kita perlu:

1) Ambil contoh USB Host untuk papan favorit Anda (saya mengambil contoh USB Host CDM STM32 dari koleksi sampel STM32F7 CubeMX);
2) Membuang prosedur inisialisasi kelas perangkat;
3) Menulis pembungkus yang nyaman untuk bekerja dengan fungsi membaca / menulis untuk mengontrol titik akhir dan titik akhir data;
4) Tulis fungsi Anda untuk mengubah data mentah menjadi sesuatu yang ditampilkan;
5) Gunakan LUT (color Look Up Table) untuk mewarnai gambar monokrom berwarna. Fitch ini muncul dalam keluarga mikrokontroler STM32, yang dapat dikontrol secara independen dengan layar LCD.

Untuk memulai, mari kita lakukan sesuatu yang mirip dengan sepotong dari libusb, yang akan membantu kita menautkan Perpustakaan HAL dengan kode berikut:

Kode prosedur dari libusb
int libusb_control_transfer(libusb_device_handle* dev_handle, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char* data, uint16_t wLength, unsigned int timeout) { hUSBHost.Control.setup.b.bmRequestType = request_type; hUSBHost.Control.setup.b.bRequest = bRequest; hUSBHost.Control.setup.b.wValue.w = wValue; hUSBHost.Control.setup.b.wIndex.w = wIndex; hUSBHost.Control.setup.b.wLength.w = wLength; int status; do { status = USBH_CtlReq(&hUSBHost, data, wLength); } while (status == USBH_BUSY); if (status != USBH_OK) { hUSBHost.RequestState = CMD_SEND; return 0; } else { return wLength; } } 


Kemudian kita pergi ke sini dan melihat prosedur vendor_transfer . Juga, tidak ada salahnya untuk memperhatikan daftar permintaan.

kode prosedur vendor_transfer
 int vendor_transfer(bool direction, uint8_t req, uint16_t value, uint16_t index, uint8_t * data, uint8_t size, int timeout) { int res; uint8_t bmRequestType = (direction ? LIBUSB_ENDPOINT_IN : LIBUSB_ENDPOINT_OUT) | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE; uint8_t bRequest = req; uint16_t wValue = value; uint16_t wIndex = index; uint8_t * aData = data; uint16_t wLength = size; if (!direction) { // to device #ifdef LOG_DEBUG USBH_UsrLog("ctrl_transfer(0x%x, 0x%x, 0x%x, 0x%x, %d)", bmRequestType, bRequest, wValue, wIndex, wLength); printf(" ["); for (int i = 0; i < wLength; i++) { printf(" %02x", data[i]); } printf(" ]\n"); #endif res = libusb_control_transfer(handle, bmRequestType, bRequest, wValue, wIndex, aData, wLength, timeout); #ifdef LOG_DEBUG if (res != wLength) { USBH_UsrLog("Bad returned length: %d\n", res); } #endif } else { // from device #ifdef LOG_DEBUG USBH_UsrLog("ctrl_transfer(0x%x, 0x%x, 0x%x, 0x%x, %d)", bmRequestType, bRequest, wValue, wIndex, wLength); #endif res = libusb_control_transfer(handle, bmRequestType, bRequest, wValue, wIndex, aData, wLength, timeout); #ifdef LOG_DEBUG if (res != wLength) { USBH_UsrLog("Bad returned length: %d\n", res); } printf(" -> ["); for (int i = 0; i < res; i++) { printf(" %02x", data[i]); } printf(" ]\n"); #endif } return res; } 


Selanjutnya, kami menulis prosedur untuk menerima gambar. Tidak ada yang istimewa untuk dikomentari, dimata-matai dalam Contoh CDC.

Prosedur penerimaan data USB
 int CAM_ProcessReception(USBH_HandleTypeDef *phost) { USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; uint16_t length = 0; uint8_t data_rx_state = CDC_RECEIVE_DATA; size = FRAME_WIDTH * FRAME_HEIGHT; int bufsize = size * sizeof(uint16_t); int bsize = 0; while (data_rx_state != CDC_IDLE) { switch(data_rx_state) { case CDC_RECEIVE_DATA: USBH_BulkReceiveData (phost, &rawdata[bsize], 512, InPipe); data_rx_state = CDC_RECEIVE_DATA_WAIT; break; case CDC_RECEIVE_DATA_WAIT: URB_Status = USBH_LL_GetURBState(phost, InPipe); /*Check the status done for reception*/ if(URB_Status == USBH_URB_DONE ) { length = USBH_LL_GetLastXferSize(phost, InPipe); bsize+= length; if(((bufsize - length) > 0) && (bsize < bufsize)) //TODO { data_rx_state = CDC_RECEIVE_DATA; } else { data_rx_state = CDC_IDLE; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); #endif } break; default: break; } } return data_rx_state; } 


Kita juga perlu menggambar data yang diterima di layar. Saya perhatikan bahwa dalam byte data ke-20, yang merupakan array 16-bit piksel, informasi tentang jenis bingkai disimpan. Ada beberapa jenis bingkai. Kami tertarik pada kerangka kalibrasi dan kerangka kerja. Bingkai kalibrasi diperoleh saat pencitraan termal menutup tirai dan mengambil gambar "kegelapan". Saat memotret bingkai normal, rana terbuka. Dengan demikian, saat bekerja, Anda selalu mendengar perangkat mengklik rana.

Prosedur menggambar layar
 void BSP_LCD_DrawArray(uint32_t Xpos, uint32_t Ypos, uint32_t width, uint32_t height, uint8_t bit_pixel, uint8_t *pbmp) { uint32_t index = 0; uint32_t index2 = 0; // uint32_t address; //uint32_t input_color_mode = 0; //uint32_t Color; static int pixel; static int calib_pixel=0; uint8_t Component; static int v; uint8_t frame_type; frame_type = *(__IO uint8_t *) (pbmp + 20); switch (frame_type) { case 6: calib_pixel = (*(uint16_t*)pbmp); minpixel = calib_pixel; //calib_pixel = bswap_16(calib_pixel); break; case 3: /* Convert picture to ARGB8888 pixel format */ for(index=0; index < height; index++) { for(index2=0; index2 < width; index2++) { pixel = (*(uint16_t*)pbmp); //pixel = bswap_16(pixel); //v = pixel - calib_pixel; //v += 0x8000; if (maxpixel < pixel) maxpixel = pixel; if (minpixel > pixel) minpixel = pixel; if (pixel < 0) { pixel = 0; } if (pixel > 0xFFFF) { pixel = 0xFFFF; } v = map(pixel, 6000, 13000, 0, 255); //v = (v - MAX) * 255 / (MIN - MAX); if (v < 0) v = 0; if (v > 255) v = 255; BSP_LCD_DrawPixel(index2+270, index+100, (0xFF << 24) | (uint8_t)v << 16 | (uint8_t)v << 8 | (uint8_t)v); pbmp += 2; } } break; case 4: break; } } 


Akhirnya, siklus utama, dari mana dapat dilihat - di mana apa yang dipotong, di mana sesuatu dimasukkan.

Siklus utama
 #define DELAY1 10 #define USB_PIPE_NUMBER 0x81 #define FRAME_WIDTH 208 #define FRAME_HEIGHT 156 uint8_t OutPipe, InPipe; uint8_t usb_device_state; uint8_t rawdata[FRAME_HEIGHT*FRAME_WIDTH*2]; uint8_t data[64]; USBH_StatusTypeDef status; uint8_t transf_size; int size; int main(void) { /* Enable the CPU Cache */ CPU_CACHE_Enable(); /* STM32F7xx HAL library initialization: - Configure the Flash ART accelerator on ITCM interface - Configure the Systick to generate an interrupt each 1 msec - Set NVIC Group Priority to 4 - Low Level Initialization */ HAL_Init(); /* Configure the System clock to have a frequency of 200 MHz */ SystemClock_Config(); /* Init CDC Application */ CDC_InitApplication(); /* Init Host Library */ USBH_Init(&hUSBHost, USBH_UserProcess, 0); /* Add Supported Class */ //USBH_RegisterClass(&hUSBHost, USBH_CDC_CLASS); /* Start Host Process */ USBH_Start(&hUSBHost); /* Run Application (Blocking mode) */ while (1) { /* USB Host Background task */ USBH_Process(&hUSBHost); if (hUSBHost.gState == HOST_CHECK_CLASS) { switch (usb_device_state) { case 1: status = USBH_Get_StringDesc(&hUSBHost,hUSBHost.device.DevDesc.iManufacturer, data , 64); if (status == USBH_OK) { USBH_UsrLog("## Manufacturer : %s", (char *)data); HAL_Delay(1000); usb_device_state = 1; } break; case 2: status = USBH_Get_StringDesc(&hUSBHost, hUSBHost.device.DevDesc.iProduct, data , 64); if (status == USBH_OK) { USBH_UsrLog("## Product : %s", (char *)data); HAL_Delay(1000); usb_device_state = 2; } break; case 0: InPipe = USBH_AllocPipe(&hUSBHost, 0x81); status = USBH_OpenPipe(&hUSBHost, InPipe, 0x81, hUSBHost.device.address, hUSBHost.device.speed, USB_EP_TYPE_BULK, USBH_MAX_DATA_BUFFER); if (status == USBH_OK) usb_device_state = 3; break; case 3: HAL_Delay(1); const uint8_t data0[2] = {0x00, 0x00}; vendor_transfer(0, SET_OPERATION_MODE, 0, 0, data0, 2); vendor_transfer(0, SET_OPERATION_MODE, 0, 0, data0, 2); vendor_transfer(0, SET_OPERATION_MODE, 0, 0, data0, 2); data[0] = 0x01; vendor_transfer(0, TARGET_PLATFORM, 0, 0, data, 1); data[0] = 0x00; data[1] = 0x00; vendor_transfer(0, SET_OPERATION_MODE, 0, 0, data); transf_size = vendor_transfer(1, GET_FIRMWARE_INFO, 0, 0, data, 4); transf_size = vendor_transfer(1, READ_CHIP_ID, 0, 0, data, 12); const uint8_t data1[6] = { 0x20, 0x00, 0x30, 0x00, 0x00, 0x00 }; vendor_transfer(0, SET_FACTORY_SETTINGS_FEATURES, 0, 0, data1, 6); transf_size = vendor_transfer(1, GET_FACTORY_SETTINGS, 0, 0, data, 64); const uint8_t data2[6] = { 0x20, 0x00, 0x50, 0x00, 0x00, 0x00 }; vendor_transfer(0, SET_FACTORY_SETTINGS_FEATURES, 0, 0, data2, 6); transf_size = vendor_transfer(1, GET_FACTORY_SETTINGS, 0, 0, data, 64); const uint8_t data3[6] = { 0x0c, 0x00, 0x70, 0x00, 0x00, 0x00 }; vendor_transfer(0, SET_FACTORY_SETTINGS_FEATURES, 0, 0, data3, 6); transf_size = vendor_transfer(1, GET_FACTORY_SETTINGS, 0, 0, data, 24); const uint8_t data4[6] = { 0x06, 0x00, 0x08, 0x00, 0x00, 0x00 }; vendor_transfer(0, SET_FACTORY_SETTINGS_FEATURES, 0, 0, data4, 6); vendor_transfer(1, GET_FACTORY_SETTINGS, 0, 0, data, 12); const uint8_t data5[2] = { 0x08, 0x00 }; vendor_transfer(0, SET_IMAGE_PROCESSING_MODE, 0, 0, data5, 2); vendor_transfer(1, GET_OPERATION_MODE, 0, 0, data,2); const uint8_t data6[2] = { 0x08, 0x00 }; vendor_transfer(0, SET_IMAGE_PROCESSING_MODE, 0, 0, data6, 2); const uint8_t data7[2] = { 0x01, 0x00 }; vendor_transfer(0, SET_OPERATION_MODE, 0, 0, data7, 2); vendor_transfer(1, GET_OPERATION_MODE, 0, 0, data, 2); USBH_UsrLog("SeeK Thermal Init Done.\n"); size = FRAME_WIDTH * FRAME_HEIGHT; int bufsize = size * sizeof(uint16_t); status = CDC_IDLE; usb_device_state = 4; break; case 4: //while(1 ){ // request a frame data[0] = (uint8_t)(size & 0xff); data[1] = (uint8_t)((size>>8)&0xff); data[2] = 0; data[3] = 0; if (status == CDC_IDLE) vendor_transfer(0, 0x53, 0, 0, data, 4); status = CAM_ProcessReception(&hUSBHost); if (status == CDC_IDLE) BSP_LCD_DrawArray(10, 10, FRAME_WIDTH, FRAME_HEIGHT, 16, rawdata); usb_device_state = 4; break; } } } } 


Kesimpulan


Pengoperasian imager termal dengan mikrokontroler terlihat jauh lebih cepat daripada dengan smartphone. Saya merekomendasikan gadget ini untuk menilai gambaran termal dari perangkat elektronik. Imager termal memiliki panjang fokus yang bisa disesuaikan, yang memungkinkan Anda untuk bahkan mempertimbangkan komponen elektronik individual di papan! Sebagai kesimpulan, sebuah video dari mana Anda dapat mengevaluasi kecepatan imager termal (sekitar 8-9 fps)



Informasi untuk pembeli potensial

Source: https://habr.com/ru/post/id402083/


All Articles