LoginSignup
0
0

M5stackCore2+Unit Camで画像を取得する

Posted at

はじめに

サンプルコードはあるのですが動かしている記事があまり見つからず。備忘録的に書き出します。

デバイス

M5stack core2

OV2640搭載 Unit Cam Wi-Fi Camera

groveケーブルもあると便利

接続

今回はPORT Aに接続します。

image.png

コード

環境はplatformIoです

main.cpp
uart_frame.cpp
uart_frame.h
main.cpp
#include <M5Core2.h>
#include "uart_frame.h"

typedef struct _JpegFrame_t
{
  uint8_t *buf;
  uint32_t size;
} JpegFrame_t;

static QueueHandle_t jpeg_fream_queue = NULL;

// UART
const int UART_RX_PIN = 33; 
const int UART_TX_PIN = 32;
const int UART_BAUD_RATE = 1500000;

void frame_recv_callback(int cmd, const uint8_t *buf, int len)
{
  JpegFrame_t frame;
  frame.buf = (uint8_t *)malloc(sizeof(uint8_t) * len);
  memcpy(frame.buf, buf, len);
  frame.size = len;

  if (xQueueSend(jpeg_fream_queue, &frame, 0) != pdTRUE)
  {
    free(frame.buf);
  }
}

void setup()
{
  M5.begin();
  Serial.begin(1500000);
   uart_frame_init(UART_RX_PIN, UART_TX_PIN, UART_BAUD_RATE);
}


void loop()
{
  JpegFrame_t frame;
  int time_last = 0;
  time_last = millis();
  xQueueReceive(jpeg_fream_queue, &frame, portMAX_DELAY);
  M5.Lcd.drawJpg(frame.buf, frame.size, 0, 0);
  Serial.printf("--%ld--size--%d--\r\n", millis() - time_last, frame.size);
  free(frame.buf);
}


core2のportAは33,32ピンに該当する。

// UART
const int UART_RX_PIN = 33; 
const int UART_TX_PIN = 32;
const int UART_BAUD_RATE = 1500000;

動作確認

サンプルコードそのままだとヌルヌル感はない。チューニングが必要だろう。

image.png

(おまけ)ライブラリ

サンプルコードリポジトリにもありますが、こちらもに転記します。

uart_frame.h
#ifndef _UART_FRAME_H
#define _UART_FRAME_H

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"

typedef enum {
    IDLE = 0x00,
    WAIT_FINISH ,
    FINISH,
} frame_state_n;

extern volatile frame_state_n frame_state;

void uart_frame_init(int32_t rx, int32_t tx, int baud);
void uart_frame_send(uint8_t cmd, const uint8_t* frame, uint32_t len, bool wait_finish);
void uart_update_pin(int32_t rx, int32_t tx);

#endif
uart_frame.cpp
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "string.h"
#include "esp_heap_caps.h"
#include "uart_frame.h"

#define UART_NUM UART_NUM_1
#define UART_QUEUE_LENGTH 10
#define TX_BUF_SIZE 0
#define FRAME_MAX_SIZE (16 * 1024)
#define RX_BUF_SIZE 2 * 1024

#define PACK_FIRST_BYTE 0xAA
#define PACK_SECOND_BYTE 0x55

volatile frame_state_n frame_state;
static QueueHandle_t uart_queue = NULL;
static QueueHandle_t uart_buffer_queue = NULL;

static void uart_frame_task(void *arg);
static void uart_frame_send_task(void *arg);

typedef struct _UartFrame_t {
  bool free_buffer;
  uint8_t* buffer;
  uint32_t len;
} UartFrame_t;

int32_t baud_rate = 1500000;
uint16_t uart_tx_pin = 26;
uint16_t uart_rx_pin = 36;

void __attribute__((weak)) frame_post_callback(uint8_t cmd) {

}

void __attribute__((weak)) frame_recv_callback(int cmd, const uint8_t*buf, int len) {

}

static void uart_base_init() {
  uart_driver_delete(UART_NUM);
  const uart_config_t uart_config = {
    .baud_rate = baud_rate,
    .data_bits = UART_DATA_8_BITS,
    .parity = UART_PARITY_DISABLE,
    .stop_bits = UART_STOP_BITS_1,
    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
  };
  uart_param_config(UART_NUM, &uart_config);
  uart_set_pin(UART_NUM, uart_tx_pin, uart_rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  uart_driver_install(UART_NUM, RX_BUF_SIZE, TX_BUF_SIZE, UART_QUEUE_LENGTH, &uart_queue, ESP_INTR_FLAG_LOWMED);
  uart_set_rx_timeout(UART_NUM, 50);
} 

void uart_frame_init(int32_t rx, int32_t tx, int baud) {
  baud_rate = baud;
  uart_rx_pin = rx;
  uart_tx_pin = tx;
  uart_buffer_queue = xQueueCreate(1, sizeof(UartFrame_t));
  uart_base_init();
  xTaskCreatePinnedToCore(uart_frame_task, "uart_queue_task", 4 * 1024, NULL, 3, NULL, 0);
  xTaskCreatePinnedToCore(uart_frame_send_task, "uart_frame_send_task", 2 * 1024, NULL, 1, NULL, 0);
}

void uart_update_pin(int32_t rx, int32_t tx) {
  uart_set_pin(UART_NUM, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

typedef enum {
  kWaitStart = 0x00, 
  kRecvLenght,
  kLenghtCheck,
  kRecvCMD,
  kRecvData,
  kCrcCheck,
  kSuccess,
} frame_state_t;

static void uart_frame_send_task(void *arg) {
  UartFrame_t frame;
  
  for (;;) {
    xQueueReceive(uart_buffer_queue, &frame, portMAX_DELAY);
    uart_wait_tx_done(UART_NUM, portMAX_DELAY);
    uart_write_bytes(UART_NUM, (const char *)frame.buffer, frame.len);
    uart_wait_tx_done(UART_NUM, portMAX_DELAY);
    frame_post_callback(frame.buffer[7]);
    if (frame.free_buffer) {
      free(frame.buffer);
    }
  }
  vTaskDelete(NULL);
}

static void uart_frame_task(void *arg) {
  uart_event_t xEvent;
  // uint32_t buf_pos = 0;

  uint8_t *buf = (uint8_t *)heap_caps_calloc(FRAME_MAX_SIZE, sizeof(uint8_t),  MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
  uint8_t *recv_buf = (uint8_t *)malloc(1024 * sizeof(uint8_t));
  uint8_t* ptr = recv_buf;
  uint32_t packet_pos = 0;
  uint8_t packet_ahead[] = {PACK_FIRST_BYTE, PACK_SECOND_BYTE};
  uint32_t frame_length = 0;
  uint8_t crc_xor = 0x00;
  uint16_t size;
  buf[0] = PACK_FIRST_BYTE;
  buf[1] = PACK_SECOND_BYTE;
  frame_state_t frame_state = kWaitStart;

  for(;;) {
    if (xQueueReceive(uart_queue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) {
      switch(xEvent.type) {
        case UART_DATA: {
          uart_read_bytes(UART_NUM, recv_buf, xEvent.size, portMAX_DELAY);
          ptr = recv_buf;
          size = xEvent.size;
          while (size) {
            switch (frame_state) {
              case kWaitStart:
                buf[packet_pos] = *ptr;
                ptr += 1;
                size -= 1;

                if (buf[packet_pos] == packet_ahead[packet_pos]) {
                  packet_pos += 1;
                  if (packet_pos == 2) {
                    frame_length = 0;
                    frame_state = kRecvLenght;

                  }
                } else {
                  packet_pos = 0;
                }
                break;

              case kRecvLenght:
                buf[packet_pos] = *ptr;
                ptr += 1;
                size -= 1;
                packet_pos += 1;
                if (packet_pos == (2 + 4)) {
                  crc_xor = 0x000;
                  frame_state = kLenghtCheck;
                }
                break;

              case kLenghtCheck:
                buf[packet_pos] = *ptr;
                ptr += 1;
                size -= 1;
                crc_xor = 0x00 ^ buf[2] ^ buf[3] ^ buf[4] ^ buf[5];
                if (crc_xor == buf[packet_pos]) {
                  packet_pos += 1;
                  frame_length = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | (buf[5] << 0);
                  if (frame_length > FRAME_MAX_SIZE - 9) {
                    packet_pos = 0;
                    frame_state = kWaitStart;
                  } else {
                    frame_state = kRecvCMD;
                  }
                } else {
                  packet_pos = 0;
                  frame_state = kWaitStart;
                }
                break;

              case kRecvCMD: {
                buf[packet_pos] = *ptr;
                ptr += 1;
                size -= 1;
                packet_pos += 1;
                frame_state = kRecvData;
                break;
              }
              
              case kRecvData:
                while(size > 0) {
                  buf[packet_pos] = *ptr;
                  ptr += 1;
                  size -= 1;
                  packet_pos += 1;
                  if (packet_pos == (frame_length + 6)) {
                    frame_state = kCrcCheck;
                    break;
                  }
                }
                break;

              case kCrcCheck:
                buf[packet_pos] = *ptr;
                ptr += 1;
                size -= 1;
                crc_xor = 0x00;

                for (uint16_t i = 0; i < packet_pos; i++) {
                  crc_xor = buf[i] ^ crc_xor;
                }

                if (crc_xor != buf[packet_pos]) {
                  packet_pos = 0;
                  frame_state = kWaitStart;
                  break;
                }

              case kSuccess:
                packet_pos = 0;
                frame_state = kWaitStart;
                frame_recv_callback(buf[7], &buf[8], frame_length - 2);
                break;

              default:
                break;
            }
          }
          break;
        }
        
        case UART_FIFO_OVF: {
          xQueueReset(uart_queue);
          break;
        }

        case UART_BUFFER_FULL: {
          uart_flush_input(UART_NUM);
          xQueueReset(uart_queue);
          break;
        }

        case UART_BREAK: {
          break;
        }

        case UART_PARITY_ERR: {
          break;
        }

        case UART_FRAME_ERR: {
          break;
        }

        default: {
          break;
        }
      }
    }
  }
  vTaskDelete(NULL);
}

void uart_frame_send(uint8_t cmd, const uint8_t* frame, uint32_t len, bool wait_finish) {
  uint32_t out_len = 9 + len;
  uint8_t* out_buf = (uint8_t *)malloc(sizeof(uint8_t) * out_len);

  out_buf[0] = PACK_FIRST_BYTE;
  out_buf[1] = PACK_SECOND_BYTE;
  out_buf[2] = (out_len - 7) >> 24;
  out_buf[3] = (out_len - 7) >> 16;
  out_buf[4] = (out_len - 7) >> 8;
  out_buf[5] = (out_len - 7);
  out_buf[6] = 0x00 ^ out_buf[2] ^ out_buf[3] ^ out_buf[4] ^ out_buf[5];
  out_buf[7] = cmd;
  memcpy(&out_buf[8], frame, len);
  int xor_resilt = 0x00;
  for (uint32_t i = 0; i < out_len - 1; i++) {
    xor_resilt = out_buf[i] ^ xor_resilt;
  }
  out_buf[out_len - 1] = xor_resilt;

  if (wait_finish) {
    while (uxQueueMessagesWaiting(uart_buffer_queue)) {
      vTaskDelay(pdMS_TO_TICKS(10));
    }
  }

  UartFrame_t uart_frame;
  uart_frame.buffer = out_buf;
  uart_frame.len = out_len;
  uart_frame.free_buffer = true;

  xQueueSend(uart_buffer_queue, &uart_frame, portMAX_DELAY);
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0