Gripporillat
Well-known member
Hi there!
I got arduino code from a manufacturer to test his development board and tried using it with a Teensy 3.5. The manufacturer wrote it for Arduino Due. At first things seemed fine. I could transmit and receive valid data over SPI. But when I do a certain operation (generate_DMX) the module stops working after a few seconds. After a long conversation with the manufacturer I decided to buy and try it with a Arduino Due just to make sure that it's not a Teensy problem.
Bad news is: it works perfectly fine with the Arduino so it must be a Teensy-related problem. But I just don't get what's wrong. Any help would be highly appreciated! I am aware that you don't own the module so you can't test it yourself but maybe you have a helpful idea.
Thank you in advance!
Robert
I got arduino code from a manufacturer to test his development board and tried using it with a Teensy 3.5. The manufacturer wrote it for Arduino Due. At first things seemed fine. I could transmit and receive valid data over SPI. But when I do a certain operation (generate_DMX) the module stops working after a few seconds. After a long conversation with the manufacturer I decided to buy and try it with a Arduino Due just to make sure that it's not a Teensy problem.
Bad news is: it works perfectly fine with the Arduino so it must be a Teensy-related problem. But I just don't get what's wrong. Any help would be highly appreciated! I am aware that you don't own the module so you can't test it yourself but maybe you have a helpful idea.
Thank you in advance!
Robert
Code:
#include <SPI.h>
#include "timo_spi.h"
#define TIMO_IDENTIFY_IRQ (1 << 5)
#define TIMO_SPI_DEVICE_BUSY_IRQ_MASK (1 << 7)
static timo_t timos[2] = {
{ .csn_pin = 10, .irq_pin = 9 },
{ .csn_pin = 7, .irq_pin = 6 }
};
static timo_t *timo = &timos[1];
static uint8_t tx_buffer[1024];
static uint8_t rx_buffer[1024];
static bool poll_pending_irqs = true;
static timo_register_info_t timo_registers[] = TIMO_REGISTERS;
void irq_pin_handler_0() {
timos[0].irq_pending = 1;
}
void irq_pin_handler_1() {
timos[1].irq_pending = 1;
}
bool irq_is_pending() {
noInterrupts();
bool pending = timo->irq_pending;
timo->irq_pending = false;
interrupts();
return pending;
}
void setup() {
Serial.begin(115200);
SPI.begin();
for (int i = 0; i < (sizeof(timos) / sizeof(timos[0])); i++) {
pinMode(timos[i].irq_pin, INPUT);
pinMode(timos[i].csn_pin, OUTPUT);
digitalWrite(timos[i].csn_pin, HIGH);
}
attachInterrupt(digitalPinToInterrupt(timos[0].irq_pin), irq_pin_handler_0, FALLING);
attachInterrupt(digitalPinToInterrupt(timos[1].irq_pin), irq_pin_handler_1, FALLING);
SPI.beginTransaction(SPISettings(250000, MSBFIRST, SPI_MODE0));
delay(1000);
while(Serial.available() > 0) {
Serial.read();
}
Serial.println("Running");
Serial.flush();
}
void loop() {
int16_t irq_flags;
static String string = "";
if (poll_pending_irqs) {
if (irq_is_pending()) {
irq_flags = timo_transfer(TIMO_NOP_COMMAND, rx_buffer, tx_buffer, 0);
Serial.print("/ Got IRQ. IRQ flags: ");
print_irq_flags(irq_flags);
if (irq_flags & TIMO_IDENTIFY_IRQ) {
Serial.print("Clearing flags by reading the STATUS register: ");
irq_flags = timo_transfer(TIMO_READ_REG_COMMAND(TIMO_STATUS_REG), rx_buffer, tx_buffer, 2);
print_response(irq_flags, rx_buffer, 1);
}
Serial.println();
Serial.flush();
}
}
while (Serial.available() > 0) {
char letter = Serial.read();
if (letter == '\n') {
process_user_input(string);
Serial.flush();
string = "";
}else {
string += letter;
}
}
}
/**
* @param len Length in bytes. IRQ flag is counted. Example: Use length 9 when reading the version register.
*/
int16_t timo_transfer(uint8_t command, uint8_t *dst, uint8_t *src, uint32_t len) {
uint8_t irq_flags;
uint32_t start_time = millis();
digitalWrite(timo->csn_pin, LOW);
irq_flags = SPI.transfer(command);
digitalWrite(timo->csn_pin, HIGH);
if (len == 0) {
return irq_flags;
}
while(!irq_is_pending()) {
if (millis() - start_time > 10000) {
return -1;
}
}
digitalWrite(timo->csn_pin, LOW);
irq_flags = SPI.transfer(0xff);
if (irq_flags & TIMO_SPI_DEVICE_BUSY_IRQ_MASK) {
digitalWrite(timo->csn_pin, HIGH);
return irq_flags;
}
for (uint32_t i = 0; i < len - 1; i++) {
*dst++ = SPI.transfer(*src++);
}
digitalWrite(timo->csn_pin, HIGH);
return irq_flags;
}
String parsed_command[4] = { "", "", "", "" };
void split(String string, String delimiter, String dst[], uint32_t dst_len) {
int prev_index = 0;
for (uint32_t i = 0; i < dst_len; i++) {
dst[i] = "";
}
for (uint32_t i = 0; i < dst_len; i++) {
int next_index = string.indexOf(delimiter, prev_index + 1);
if (next_index == -1) {
dst[i] = string.substring(prev_index, string.length());
dst[i].trim();
break;
} else {
dst[i] = string.substring(prev_index, next_index);
dst[i].trim();
}
prev_index = next_index;
}
}
uint8_t hex_nibble_to_val(char ascii) {
if (ascii >= '0' && ascii <= '9') {
return ascii - '0';
} else if (ascii >= 'A' && ascii <= 'F') {
return ascii - 'A' + 10;
} else if (ascii >= 'a' && ascii <= 'f') {
return ascii - 'a' + 10;
}
Serial.print("! ");
Serial.print("0x");
Serial.print(ascii, HEX);
Serial.println(" is not a valid hex symbol");
return 0;
}
void hex_to_bytes(String string, uint8_t *dst, uint32_t dst_len) {
if (string.length() % 2 != 0) {
Serial.println("! Expecting hex string length to be a multiple of 2. Example: Send '04', not '4'.");
return;
}
for (uint32_t i = 0; i < string.length() / 2; i++) {
if (i >= dst_len) {
return;
}
*dst = hex_nibble_to_val(string.charAt(i * 2)) * 16;
*dst += hex_nibble_to_val(string.charAt(i * 2 + 1));
dst++;
}
}
int hex_to_int(String string) {
int result = 0;
for (int i = 0; i < string.length(); i++) {
result <<= 4;
result |= hex_nibble_to_val(string.charAt(i));
}
return result;
}
timo_register_info_t* find_register(String name) {
for (int i = 0; i < (sizeof(timo_registers) / sizeof(timo_registers[0])); i++) {
timo_register_info_t *reg = &timo_registers[i];
if (String(reg->name).equals(name)) {
return reg;
}
}
return NULL;
}
void process_user_input(String string) {
int16_t irq_flags;
Serial.print("> ");
Serial.flush();
Serial.println(string);
Serial.flush();
split(string, " ", parsed_command, sizeof(parsed_command)/sizeof(parsed_command[0]));
if (parsed_command[0] == "read" || parsed_command[0] == "read_reg") {
parsed_command[0] = "READ_REG";
} else if (parsed_command[0] == "write" || parsed_command[0] == "write_reg") {
parsed_command[0] = "WRITE_REG";
}
if (parsed_command[0] == "NOP") {
irq_flags = timo_transfer(TIMO_NOP_COMMAND, rx_buffer, tx_buffer, 0);
print_response(irq_flags, rx_buffer, 0);
} else if (parsed_command[0] == "READ_REG") {
parsed_command[1].toUpperCase();
timo_register_info_t *reg = find_register(parsed_command[1]);
if (reg == NULL) {
Serial.println("! " + parsed_command[0] + " Unknown register");
} else {
if (reg->read_access) {
irq_flags = timo_transfer(TIMO_READ_REG_COMMAND(reg->address), rx_buffer, tx_buffer, reg->length + 1);
print_response(irq_flags, rx_buffer, reg->length);
} else {
Serial.println("! " + parsed_command[0] + " Not allowed to read");
}
}
} else if (parsed_command[0] == "WRITE_REG") {
parsed_command[1].toUpperCase();
timo_register_info_t *reg = find_register(parsed_command[1]);
if (reg == NULL) {
Serial.println("! " + parsed_command[0] + " Unknown register");
} else {
if (reg->write_access) {
hex_to_bytes(parsed_command[2], tx_buffer, sizeof(tx_buffer));
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(reg->address), rx_buffer, tx_buffer, reg->length + 1);
print_response(irq_flags, rx_buffer, 0);
} else {
Serial.println("! " + parsed_command[0] + " Not allowed to write");
}
}
} else if (parsed_command[0] == "READ_DMX") {
memset(tx_buffer, 0xff, sizeof(tx_buffer));
int read_length = hex_to_int(parsed_command[1]);
if (read_length > 128) {
Serial.print("! " + parsed_command[0] + " Invalid length: ");
Serial.print(read_length);
Serial.println(" (max is 128)");
} else {
irq_flags = timo_transfer(TIMO_READ_DMX_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
}
} else if (parsed_command[0] == "FW_BLOCK_CMD_1") {
poll_pending_irqs = false;
irq_is_pending();
hex_to_bytes(parsed_command[1], tx_buffer, sizeof(tx_buffer));
irq_flags = timo_transfer(TIMO_FW_BLOCK_CMD_1_COMMAND, rx_buffer, tx_buffer, 255);
while(!irq_is_pending());
print_response(irq_flags, rx_buffer, 0);
} else if (parsed_command[0] == "FW_BLOCK_CMD_2") {
poll_pending_irqs = false;
irq_is_pending();
hex_to_bytes(parsed_command[1], tx_buffer, sizeof(tx_buffer));
irq_flags = timo_transfer(TIMO_FW_BLOCK_CMD_2_COMMAND, rx_buffer, tx_buffer, 19);
while(!irq_is_pending());
print_response(irq_flags, rx_buffer, 0);
} else if (parsed_command[0] == "disable_irq_polling") {
poll_pending_irqs = false;
} else if (parsed_command[0] == "enable_irq_polling") {
poll_pending_irqs = true;
} else if (parsed_command[0] == "generate_DMX") {
uint16_t n_channels = 512;
uint16_t interslot_time = 0;
uint32_t refresh_period = 25000;
tx_buffer[0] = n_channels >> 8;
tx_buffer[1] = n_channels;
tx_buffer[2] = interslot_time >> 8;
tx_buffer[3] = interslot_time;
tx_buffer[4] = refresh_period >> 24;
tx_buffer[5] = refresh_period >> 16;
tx_buffer[6] = refresh_period >> 8;
tx_buffer[7] = refresh_period;
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(TIMO_DMX_SPEC_REG), rx_buffer, tx_buffer, 1 + 8);
tx_buffer[0] = 1;
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(TIMO_DMX_CONTROL_REG), rx_buffer, tx_buffer, 1 + 1);
for(uint16_t i = 0; i < 256; i++) {
tx_buffer[i] = i;
}
for(uint16_t i = 0; i < 256; i++) {
tx_buffer[256+i] = 255 - i;
}
irq_flags = timo_transfer(TIMO_WRITE_DMX_COMMAND, rx_buffer, tx_buffer, 1 + 128);
irq_flags = timo_transfer(TIMO_WRITE_DMX_COMMAND, rx_buffer, tx_buffer + (1 * 128), 1 + 128);
irq_flags = timo_transfer(TIMO_WRITE_DMX_COMMAND, rx_buffer, tx_buffer + (2 * 128), 1 + 128);
irq_flags = timo_transfer(TIMO_WRITE_DMX_COMMAND, rx_buffer, tx_buffer + (3 * 128), 1 + 128);
} else if (parsed_command[0] == "read_full_DMX_frame") {
uint16_t window_size = 512;
uint16_t start_address = 0;
tx_buffer[0] = window_size >> 8;
tx_buffer[1] = window_size;
tx_buffer[2] = start_address >> 8;
tx_buffer[3] = start_address;
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(TIMO_DMX_WINDOW_REG), rx_buffer, tx_buffer, 1 + 4);
uint8_t read_length = 128;
irq_flags = timo_transfer(TIMO_READ_DMX_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_DMX_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_DMX_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_DMX_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
}
else if (parsed_command[0] == "read_ASC_FRAME") {
uint8_t start_code = 0;
uint16_t asc_frame_length = 512;
tx_buffer[0] = asc_frame_length >> 8;
tx_buffer[1] = asc_frame_length;
tx_buffer[2] = start_code;
//tx_buffer[2] = asc_frame_length >> 8;
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(TIMO_ASC_FRAME_REG), rx_buffer, tx_buffer, 1 + 3);
uint8_t read_length = 128;
irq_flags = timo_transfer(TIMO_READ_ASC_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_ASC_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_ASC_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
irq_flags = timo_transfer(TIMO_READ_ASC_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
}
else if (parsed_command[0] == "LINK_QUALITY") {
uint8_t pdr = 0;
tx_buffer[0] = pdr;
irq_flags = timo_transfer(TIMO_WRITE_REG_COMMAND(TIMO_LINK_QUALITY_REG), rx_buffer, tx_buffer, 1 + 1);
uint8_t read_length = 128;
irq_flags = timo_transfer(TIMO_READ_ASC_COMMAND, rx_buffer, tx_buffer, 1 + read_length);
print_response(irq_flags, rx_buffer, read_length);
}
else {
Serial.println("! Unknown command");
}
Serial.flush();
}
char nibble_to_hex(uint8_t nibble) {
nibble &= 0xf;
if (nibble >= 0 && nibble <= 9) {
return '0' + nibble;
} else {
return 'A' + nibble - 10;
}
}
void print_response(int16_t irq_flags, uint8_t *data, uint32_t len) {
if (irq_flags < 0) {
Serial.println("! Timeout");
return;
}
Serial.print("< ");
print_irq_flags(irq_flags);
Serial.print(" ");
Serial.flush();
for (uint32_t i = 0; i < len; i++) {
Serial.print(nibble_to_hex(0xf & (data[i] >> 4)));
Serial.print(nibble_to_hex(0xf & data[i]));
Serial.flush();
}
Serial.println();
}
void print_irq_flags(int16_t irq_flags) {
for (int i = 7; i >= 0; i--) {
if (irq_flags & (1 << i)) {
Serial.print('1');
} else {
Serial.print('0');
}
}
Serial.flush();
}