|
发表于 2024-7-7 10:13:00
|
显示全部楼层
谢谢,我参考的这个https://www.eevblog.com/forum/be ... 49-laser-driver-ic/
max3949.cpp
// Created by SoaSystem Engineering 2020 for Pulse-Duino Project
// In God The Merciful, The Provider of Intelligence and Knowledge
// software based 3-wires communication, custom I2C protocol
// to emulate open drain (I2C) IO with pull up resistors present
#include "max3949.h"
void csel_low() {
pinMode(CSEL_PIN, OUTPUT);
}
void csel_high() {
pinMode(CSEL_PIN, INPUT);
}
void sda_low() {
pinMode(SDA_PIN, OUTPUT);
}
void sda_high() {
pinMode(SDA_PIN, INPUT);
}
void scl_low() {
pinMode(SCL_PIN, OUTPUT);
}
void scl_high() {
pinMode(SCL_PIN, INPUT);
}
// initialize serial comm
void init_comm() {
csel_high();
scl_low();
delayMicroseconds(COMM_DELAY);
}
// finish comm, preparing idle state
void close_comm() {
delayMicroseconds(COMM_WIDTH);
scl_high();//input
sda_high();//input
csel_low();//output
}
void send_addr(byte addr) {
byte bits = 7;
// sending 7 bits register address
while (bits--) {
// send data (MSB) while clock low
if (addr & 128) {
sda_high();
} else {
sda_low();
};
delayMicroseconds(COMM_WIDTH);
scl_high();
delayMicroseconds(COMM_WIDTH);
scl_low();
addr <<= 1;
};
}
byte read_value() {
byte res, bits = 8;
// reading 8 bits register value
while (bits--) {
// ready receiving register value (clock low)
delayMicroseconds(COMM_WIDTH);
// MAX3949 should start sending next bit of register value here
scl_high();
delayMicroseconds(COMM_WIDTH);
scl_low();
// get next bit
if (digitalRead(SDA_PIN)) {
res |= 1;
} else {
res &= 254;
};
res <<= 1;//MSB first
};
return res;
}
void send_value(byte value) {
byte bits = 8;
// sending 8 bits register value
while (bits--) {
// send data (MSB) while clock low
if (value & 128) {
sda_high();
} else {
sda_low();
};
value <<= 1;
delayMicroseconds(COMM_WIDTH);
scl_high();
delayMicroseconds(COMM_WIDTH);
scl_low();
};
}
void write_register(byte addr, byte value) {
init_comm();
send_addr(addr);
// send write flag
sda_low();
delayMicroseconds(COMM_WIDTH);
scl_high();
delayMicroseconds(COMM_WIDTH);
scl_low();
send_value(value);
close_comm();
}
// just to make sure
void MAX3949_Init() {
pinMode(CSEL_PIN, OUTPUT);
digitalWrite(CSEL_PIN, LOW);
pinMode(SDA_PIN, OUTPUT);
digitalWrite(SDA_PIN, LOW);
pinMode(SCL_PIN, OUTPUT);
digitalWrite(SCL_PIN, LOW);
csel_low();
sda_high();
scl_high();
}
byte MAX3949_Read_Register(byte addr) {
init_comm();
send_addr(addr);
// send read flag
sda_high();
delayMicroseconds(COMM_WIDTH);
scl_high();
delayMicroseconds(COMM_WIDTH);
scl_low();
byte res = read_value();
close_comm();
return res;
}
void MAX3949_Write_Register(byte addr, byte value, bool broadcast) {
if (addr != 0x0E) {
// write in broadcast mode
if (broadcast) {
write_register(0x0E, 0xC9);
// write in setup mode
} else {
write_register(0x0E, 0x12);
};
delayMicroseconds(COMM_WIDTH);
};
// write the register
write_register(addr, value);
main
// Created by SoaSystem Engineering 2020 for Pulse-Duino Project
// In God The Merciful, The Provider of Intelligence and Knowledge
// receiver: MAX3949 Laser Driver IC
// ref: MAX3949 11.3Gbps laser driver.pdf (page 21)
// code for Arduino Nano (atMega328P CKOUT fuse programmed for pin D8 (PB0/CLKO) as 16MHz clock output, page 36, 86, 301)
#include "max3949.h"
// default TXCTRL register value to normal polarity (TX_POL = 1),
// de-emphasize 9% and transmit active (TX_EN = 1)
#define TXCTRL_VAL B00011011
// other MAX3949 parms
#define IMAX 245 // laser maximum current modulation
#define IMIN 5 // laser minimum current modulation
byte cur_imod; // currently set laser current modulation
#define LED_PIN 13 // warning led D13
#define FAULT_DETECT A2 // fault pin from MAX3949
#define CLK_CTL 6 // clock suppression control
#define ANA1_MAX 30 // resolution of analog trimpot value
#define ANA1_PIN A1 // analog trimpot value input
#define LED_RATE 1000 // milliseconds
#define LED_MODULO (LED_RATE / 8)
byte led_bit = 0;
// 2 seconds delay timer
#define ELAPSE2S 2000
unsigned long tmr2sta, tmr2cur;
// analog trimpot adc value
int ana1_val = 0;
#define ledOn() digitalWrite(LED_PIN, HIGH)
#define ledOff() digitalWrite(LED_PIN, LOW)
// clock control cannot produce output HI. circuit may get damaged
#define clockOn() pinMode(CLK_CTL, INPUT)
#define clockOff() pinMode(CLK_CTL, OUTPUT)
#define clockInit() digitalWrite(CLK_CTL, LOW)
void restart_max3949() {
// note: using MAX3949 datasheet diagram page 8, IMODMAX / SET_IMOD can be
// set to 200+ but if only AC coupling on the output, care must be taken to avoid
// excessive voltage swing, otherwise FAULT signal is thrown. hence reduce
// IMODMAX / SET_IMOD values.
MAX3949_Write_Register(REG_IMODMAX, IMAX);
MAX3949_Write_Register(REG_SET_IMOD, IMIN);
cur_imod = IMIN;
// biasing not applicable
MAX3949_Write_Register(REG_IBIASMAX, 0x00);
MAX3949_Write_Register(REG_SET_IBIAS, 0x00);
// other tuning parms
MAX3949_Write_Register(REG_SET_TXEQ, 0x03);
// start pulser. set MAX3949 register TXCTRL to normal polarity (TX_POL = 1),
// de-emphasize 9% and transmit active (TX_EN = 1)
MAX3949_Write_Register(REG_TXCTRL, TXCTRL_VAL);
};
void setup() {
// init led pin can be change to D13
pinMode(LED_PIN, OUTPUT);
ledOff();
// supress 16MHz signal for a while during setup
clockOff();
clockInit();
// init MAX3949 and Serial for debug
MAX3949_Init();
Serial.begin(9600);
delay(100);
// release 16MHz signal to circuitry and start max3949 pulser
restart_max3949();
clockOn();
// init elapse timer
tmr2sta = millis();
};
void blinkLed() {
byte cur_led_bit = (millis() % LED_RATE) / LED_MODULO;
if (led_bit & (1 << cur_led_bit)) ledOn();
else ledOff();
};
// update every 2 seconds
void slow_loop() {
String str;
int R05, R06, R07;
// reading trimpot analog value
ana1_val = analogRead(ANA1_PIN);
ana1_val = map(ana1_val, 0, 1023, 0, ANA1_MAX);
ana1_val = IMIN + (ana1_val * ((IMAX - IMIN) / ANA1_MAX));
// set new laser current modulation
if (ana1_val != cur_imod) {
cur_imod = ana1_val;
MAX3949_Write_Register(REG_SET_IMOD, cur_imod);
};
// report register value
str = "Reading Register 0x05 (TXCTRL) = ";
R05 = MAX3949_Read_Register(REG_TXCTRL);
str += R05;
Serial.println(str);
// report register value
str = "Reading Register 0x06 (TXSTAT1) = ";
R06 = MAX3949_Read_Register(REG_TXSTAT1);
str += R06;
Serial.println(str);
// report register value
str = "Reading Register 0x07 (TXSTAT2) = ";
R07 = MAX3949_Read_Register(REG_TXSTAT2);
str += R07;
Serial.println(str);
// report trimpot value
str = "Register 0x09 (SET_IMOD) = ";
str += ana1_val;
Serial.println(str);
Serial.println("");
// check MAX3949 error status (page 24)
if (digitalRead(FAULT_DETECT) == HIGH) {
led_bit = 255; // always lit LED. if MAX3949's fault pin is HI (hard fault condition)
} else if (R06 & 128) { // TXSTAT1, D7
led_bit = 1; // 1x short blink. Vcc below 2.3V (should be cleared short after startup)
} else if (R06 & 32) { // TXSTAT1, D5
led_bit = 5; // twice short blink. no/low (user) AC signal at inputs
} else if (R06 & 30) { // TXSTAT1, D1-D4
led_bit = 15; // 1x long led blink. other soft faults (refer to page 24)
} else if (R07 & 12) { // TXSTAT2, D2-D3
led_bit = 47; // long + short led blink. soft faults on TXSTAT2
} else { // all relevant bits cleared
led_bit = 0; // no fault. pulser should appear on the output
};
// check if TXCTRL value is not appropriate (due to arduino reset) TXCTRL_VAL
if (R05 != TXCTRL_VAL) restart_max3949();
};
void loop() {
tmr2cur = millis();
if (tmr2cur < tmr2sta) tmr2sta = tmr2cur;
if ((tmr2cur - tmr2sta) > ELAPSE2S) {
slow_loop();
tmr2sta = tmr2cur;
};
// blink led (error) status
blinkLed();
}; |
|