parent
4c10e85cb8
commit
dea2a2addb
@ -0,0 +1,78 @@
|
|||||||
|
#include "MLX75306.hpp"
|
||||||
|
|
||||||
|
MLX75306::MLX75306(SPI_HandleTypeDef SPI_handle, Chip_select_pin SPI_CS) :
|
||||||
|
SPI_handle(SPI_handle), SPI_CS(SPI_CS){ }
|
||||||
|
|
||||||
|
void MLX75306::Init(){
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX75306::Reset(){
|
||||||
|
Command(Commands::Chip_reset, { 0, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX75306::Wake_up(){
|
||||||
|
Command(Commands::Wake_up, { 0, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX75306::Zebra_pattern_1(){
|
||||||
|
Command(Commands::Test_zebra_pattern_1, { 0, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
array<uint8_t, 159> MLX75306::Read_all_8bit(){
|
||||||
|
// Command is set to read all pixels
|
||||||
|
return Command<159>(Commands::Read_out_8b, { 0x02, 0x8f });
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX75306::Integrate(double time_us){
|
||||||
|
const unsigned int f_RCO = 10000000;
|
||||||
|
const double min_time_us = 0.1;
|
||||||
|
const double max_time_us = 100000;
|
||||||
|
int64_t integration_register = 0;
|
||||||
|
|
||||||
|
// Cap values
|
||||||
|
if (time_us < min_time_us) {
|
||||||
|
time_us = min_time_us;
|
||||||
|
}
|
||||||
|
if (time_us > max_time_us) {
|
||||||
|
time_us = max_time_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate value for short integration
|
||||||
|
integration_register = ((time_us / 1000000) * f_RCO) + 4;
|
||||||
|
|
||||||
|
// If integration time is longer then maximal short integration time used long integration command
|
||||||
|
if (integration_register > ((1 << 16) - (11 * 16))) {
|
||||||
|
integration_register = (((time_us / 1000000) * f_RCO) - 11) / 16;
|
||||||
|
|
||||||
|
|
||||||
|
// Handle overflow and underflow of integration register
|
||||||
|
if (integration_register > (1 << 16)) {
|
||||||
|
integration_register = (1 << 16) - 1;
|
||||||
|
} else if (integration_register < 0) {
|
||||||
|
integration_register = 1;
|
||||||
|
}
|
||||||
|
// Long integration
|
||||||
|
Command(Commands::Start_integration_long,
|
||||||
|
{
|
||||||
|
static_cast<uint8_t>((integration_register & 0xff00) >> 8),
|
||||||
|
static_cast<uint8_t>(integration_register & 0xff)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Short integration
|
||||||
|
Command(Commands::Start_integration,
|
||||||
|
{
|
||||||
|
static_cast<uint8_t>((integration_register & 0xff00) >> 8),
|
||||||
|
static_cast<uint8_t>(integration_register & 0xff)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} // MLX75306::Integrate
|
||||||
|
|
||||||
|
MLX75306::Status_byte MLX75306::Status(){
|
||||||
|
array<uint8_t, 2> payload = { 0, 0 };
|
||||||
|
auto status = Command(Commands::Idle, payload)[0];
|
||||||
|
Status_byte status_struct = *((Status_byte *) &(status));
|
||||||
|
return status_struct;
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
/**
|
||||||
|
* @file SPI_camera.hpp
|
||||||
|
* @author Petr Malaník (TheColonelYoung(at)gmail(dot)com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 1.03.2023
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "stm32l4xx_hal.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Linear optical sensor array, including a 142 x 1 array of photodiodes
|
||||||
|
* associated charge amplifier circuitry and a pixel data-hold function that
|
||||||
|
* provides simultaneous integration start and stop times for all pixels.
|
||||||
|
*/
|
||||||
|
class MLX75306
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Describes GPIO which serves as SPI chip select pin
|
||||||
|
*/
|
||||||
|
struct Chip_select_pin {
|
||||||
|
GPIO_TypeDef *port;
|
||||||
|
uint16_t pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Command for MLX75306, whole command composes of 3 bytes, first byte is from enum below
|
||||||
|
* Other two bytes are payload which could be command specific or empty
|
||||||
|
*/
|
||||||
|
enum class Commands: uint8_t {
|
||||||
|
Idle = 0b00000000,
|
||||||
|
Chip_reset = 0b11110000,
|
||||||
|
Read_thresholds = 0b11011000,
|
||||||
|
Write_thresholds = 0b11001100,
|
||||||
|
Start_integration = 0b10111000,
|
||||||
|
Start_integration_long = 0b10110100,
|
||||||
|
Read_out_1b = 0b10011100,
|
||||||
|
Read_out_1b5 = 0b10010110,
|
||||||
|
Read_out_4b = 0b10010011,
|
||||||
|
Read_out_8b = 0b10011001,
|
||||||
|
Test_zebra_pattern_1 = 0b11101000,
|
||||||
|
Test_zebra_pattern_2 = 0b11100100,
|
||||||
|
Test_zebra_pattern_12 = 0b11100010,
|
||||||
|
Test_zebra_pattern_0 = 0b11100001,
|
||||||
|
Sleep_mode = 0b11000110,
|
||||||
|
Wake_up = 0b11000011,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure of MLX75306 status byte
|
||||||
|
*/
|
||||||
|
struct __attribute__((packed)) __attribute__((__may_alias__)) Status_byte{
|
||||||
|
uint8_t command_counter : 5; // Counter of valid commands
|
||||||
|
uint8_t device_mode : 1; // Device mode: 0-Test 1-User
|
||||||
|
uint8_t power_up_in_progress : 1; // Set after first Chip_reset command, clear after power-up
|
||||||
|
uint8_t operational_mode : 1; // Device operational mode: 0-Sleep 1-Normal
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief HAL handle of SPI to which is ArduChip connected
|
||||||
|
*/
|
||||||
|
SPI_HandleTypeDef SPI_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO description which serves as SPI Chip select
|
||||||
|
*/
|
||||||
|
Chip_select_pin SPI_CS;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new MLX75306 object
|
||||||
|
*
|
||||||
|
* @param SPI_handle HAL handle of SPI to which is sensor connected
|
||||||
|
* @param SPI_CS GPIO description which serves as SPI Chip select
|
||||||
|
*/
|
||||||
|
MLX75306(SPI_HandleTypeDef SPI_handle, Chip_select_pin SPI_CS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize sensor by reset
|
||||||
|
*/
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset sensor, reset must be done after power-up, reset all registers
|
||||||
|
*/
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change operational mode of sensor to Normal
|
||||||
|
* During normal mode an integration and readout could be performed.
|
||||||
|
*/
|
||||||
|
void Wake_up();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change operational mode of sensor to Sleep
|
||||||
|
* During sleep mode an integration and readout could not be performed.
|
||||||
|
* But power draw of sensor is reduced.
|
||||||
|
*/
|
||||||
|
void Sleep_mode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sensor will charge photodiodes to defined levels to create test pattern
|
||||||
|
* Every odd pixel is charged to high level of charge, even pixel to low level of charge
|
||||||
|
* This command is used instead of Integration start
|
||||||
|
*/
|
||||||
|
void Zebra_pattern_1();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Time in micro second to integrate charge photodiodes
|
||||||
|
* The shortest time is 0.1 us, the longest is 100 ms, values above or below are capped
|
||||||
|
*/
|
||||||
|
void Integrate(double time_us);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads Status byte of sensor by using Idle command
|
||||||
|
*
|
||||||
|
* @return Status_byte Structured status byte of sensor
|
||||||
|
*/
|
||||||
|
Status_byte Status();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform readout of all output registers and pixels from sensor
|
||||||
|
*
|
||||||
|
* @return array<uint8_t, 159> Output registers of sensor containing metadata and pixels
|
||||||
|
*/
|
||||||
|
array<uint8_t, 159> Read_all_8bit();
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send command to sensor and return answer (mostly status byte and empty bytes)
|
||||||
|
*
|
||||||
|
* @tparam array_size Size of returned answer on bytes, default is 3
|
||||||
|
* @param command Command from available Commands of sensor
|
||||||
|
* @param payload Payload (parameters) of command, mostly empty but could contain integration time, atc.
|
||||||
|
* @return array<uint8_t, array_size> Answer to command, example: status byte, readout bytes, etc.
|
||||||
|
*/
|
||||||
|
template <size_t array_size = 3>
|
||||||
|
array<uint8_t, array_size> Command(Commands command, array<uint8_t, 2> payload){
|
||||||
|
array<uint8_t, array_size> byte_stream = { 0 };
|
||||||
|
byte_stream[0] = (uint8_t) command;
|
||||||
|
byte_stream[1] = payload[0];
|
||||||
|
byte_stream[2] = payload[1];
|
||||||
|
|
||||||
|
return Transmit_and_receive(byte_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit bytes to sensor and receive answer
|
||||||
|
*
|
||||||
|
* @tparam array_size Amount of bytes to transfer and receive
|
||||||
|
* @param byte_stream Array of bytes to transmit
|
||||||
|
* @return array<uint8_t, array_size> Array of received bytes
|
||||||
|
*/
|
||||||
|
template <size_t array_size>
|
||||||
|
array<uint8_t, array_size> Transmit_and_receive(array<uint8_t, array_size> &byte_stream){
|
||||||
|
array<uint8_t, array_size> received = { 0 };
|
||||||
|
CS_enable();
|
||||||
|
HAL_SPI_TransmitReceive(&SPI_handle, byte_stream.data(), received.data(), byte_stream.size(), byte_stream.size());
|
||||||
|
CS_disable();
|
||||||
|
return received;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables communication with sensor via SPI, CS signal is active low
|
||||||
|
*/
|
||||||
|
void CS_enable(){ HAL_GPIO_WritePin(SPI_CS.port, SPI_CS.pin, GPIO_PIN_RESET); };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables communication with sensor via SPI, CS signal is active low
|
||||||
|
*/
|
||||||
|
void CS_disable(){ HAL_GPIO_WritePin(SPI_CS.port, SPI_CS.pin, GPIO_PIN_SET); };
|
||||||
|
};
|
Loading…
Reference in new issue