Перейти к публикации

Рекомендованные сообщения

Опубликовано:

Как минимум два человека (кроме меня) заинтересованы этой темой. Хорошо иметь возможность писать какой-то свой код, а не быть привязанным к MMJoy2, как бы хорош он ни был. В самом деле, есть DCS BIOS, который про TLE5010 не знает, есть платки Blue Pill (и не только они), которые в чём-то поинтереснее Ардуино... Я немного переписал опубликованный ранее код и убедился, что он на моём самодельном джойстике работает. Вопрос, конечно, насколько эффективно. Скажем, не следует ли заменить shiftIn/shiftOut и/или atan2 на что-то другое.

 

// эти пины использует mmjoy2
#define B6 10
#define B3 14
#define B1 15

// Этими выбираются два датчика TLE5010 
#define SEL1 8 //B4
#define SEL2 9 //B5

void setup() {
  unsigned char sreg;
  Serial.begin(9600);

  /* Save global interrupt flag */
  sreg = SREG;
  /* Disable interrupts */
  //__disable_interrupt();
  cli();     
  TCCR1A = 0x23;
  TCCR1B = 0x19;
  TCCR1C = 0x00;
  OCR1A = 3;
  OCR1B = 1;
  /* Restore global interrupt flag */
  SREG = sreg;

  pinMode(B6, OUTPUT); // B6 
  pinMode(B3, OUTPUT); // B3 
  pinMode(B1, OUTPUT); // B1 

  pinMode(SEL1, OUTPUT); // select
  pinMode(SEL2, OUTPUT); // select

  digitalWrite(SEL1, HIGH);
  digitalWrite(SEL2, HIGH);

}

void loop() {
  unsigned char sreg;
  double angle1=tle5010_angle(SEL1);
  double angle2=tle5010_angle(SEL2);
  delay(1500); 
  Serial.print(round(angle1));
  Serial.print(" ");
  Serial.println(round(angle2));
}


double tle5010_angle(int selection_pin){
  unsigned char xl, xh, yl, yh, crc, dummy;
  int x, y;  

  digitalWrite(selection_pin, LOW); // выбрал устройство
  
  pinMode(B3, OUTPUT); 
  digitalWrite(B1, LOW);
  shiftOut(B3, B1, MSBFIRST, 0); // B00000000 - update command!!
  digitalWrite(B1, HIGH);
  
  dummy = shiftIn(B3, B1, MSBFIRST); //?
     
                          // rw 0=write, 1=read
  unsigned char command;  // rw a3 a2 a1 a0 n2 n1 n0
  command  = 0x85;        //  1  0  0  0  0  1  0  1 = читать 5 байтов, начиная с нулевого
  
  digitalWrite(B1, LOW);  
  shiftOut(B3, B1, MSBFIRST, command);
  digitalWrite(B1, HIGH);

  pinMode(B3, INPUT_PULLUP); 
  digitalWrite(B1, LOW);
  dummy = shiftIn(B3, B1, MSBFIRST);
  xl    = shiftIn(B3, B1, MSBFIRST);
  xh    = shiftIn(B3, B1, MSBFIRST);
  yl    = shiftIn(B3, B1, MSBFIRST);
  yh    = shiftIn(B3, B1, MSBFIRST);
  crc   = shiftIn(B3, B1, MSBFIRST);
  dummy = shiftIn(B3, B1, MSBFIRST);

  digitalWrite(B1, HIGH);
  digitalWrite(selection_pin, HIGH);
  
  x = (int)(xl | (xh <<8));
  y = (int)(yl | (yh <<8));
  double angle = atan2((double)y,(double)x) / M_PI * 180 ;
  return angle;
}

 

Опубликовано:

vvm13ru
так допишите уже и проверку CRC.
 

//расчет CRC8
uint8_t MathCRC8(uint8_t crc, uint8_t data)
{
	crc ^= data;
	for (uint8_t bit=0 ; bit<8 ; bit++ ) { if ((crc&0b10000000)!=0) { crc <<= 1; crc ^= 0x1D; } else { crc <<= 1; }; };
	return(crc);
};
//расчет контрольки
//crc = 0xFF;		
//crc = MathCRC8(crc, 0b00000000); //0_0000_000 (update all TLE5011)
//crc = MathCRC8(crc, 0b10001100); //1_0001_100 (read TLE5011 4 bytes)	 
crc = 0xFB;		
crc = MathCRC8(crc, tle5010_lnk[0]);
crc = MathCRC8(crc, tle5010_lnk[1]);
crc = MathCRC8(crc, tle5010_lnk[2]);
crc = MathCRC8(crc, tle5010_lnk[3]);				
crc = (~crc)&(0b11111111);
//проверка контрольки
if (crc == tle5010_lnk[4])
{
  //расчет математики и бла-бла-бла
};

 

9 часов назад, vvm13ru сказал:

command = 0x85; // 1 0 0 0 0 1 0 1 = читать 5 байтов, начиная с нулевого

 

9 часов назад, vvm13ru сказал:

dummy = shiftIn(B3, B1, MSBFIRST);
xl = shiftIn(B3, B1, MSBFIRST);
xh = shiftIn(B3, B1, MSBFIRST);
yl = shiftIn(B3, B1, MSBFIRST);
yh = shiftIn(B3, B1, MSBFIRST);
crc = shiftIn(B3, B1, MSBFIRST);
dummy = shiftIn(B3, B1, MSBFIRST);


и вот эти костыли требуют переосмысления

  • Нравится 1
  • Спасибо! 1
Опубликовано:

Спасибо.

Что-то CRC у меня не получается.

// standard pins used by mmjoy
#define B6_GEN 10
#define B3_MISO 14
#define B1_SCK 15

// two TLE5010 chips selected by B4 and B5
#define NOT_CHIP_SELECT_1 8 //B4 // имя начинается с NOT, потому что выбрано - LOW, не выбрано - HIGH
#define NOT_CHIP_SELECT_2 9 //B5

void setup() {
  unsigned char sreg;
  Serial.begin(9600);

  /* Save global interrupt flag */
  sreg = SREG;
  /* Disable interrupts */
  //__disable_interrupt();
  cli();     
  TCCR1A = 0x23;
  TCCR1B = 0x19;
  TCCR1C = 0x00;
  OCR1A = 3;
  OCR1B = 1;
  /* Restore global interrupt flag */
  SREG = sreg;

  pinMode(B6_GEN, OUTPUT); // B6_GEN 
  pinMode(B3_MISO, OUTPUT); // B3_MISO 
  pinMode(B1_SCK, OUTPUT); // B1_SCK 

  pinMode(NOT_CHIP_SELECT_1, OUTPUT); // select
  pinMode(NOT_CHIP_SELECT_2, OUTPUT); // select

  digitalWrite(NOT_CHIP_SELECT_1, HIGH);
  digitalWrite(NOT_CHIP_SELECT_2, HIGH);

}

void loop() {
  double angle1=tle5010_angle(NOT_CHIP_SELECT_1);
  double angle2=tle5010_angle(NOT_CHIP_SELECT_2);
  delay(500); 
  Serial.print(" G ");
  Serial.print(round(angle1));
  Serial.print(" ");
  Serial.println(round(angle2));
}


double tle5010_angle(int not_chip_select){
  digitalWrite(not_chip_select, LOW); // выбрал устройство
  
  pinMode(B3_MISO, OUTPUT); 
  digitalWrite(B1_SCK, LOW);
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, 0);     // B00000000 - update command!! 
  digitalWrite(B1_SCK, HIGH);                 
  
  unsigned char dummy;
  dummy = shiftIn(B3_MISO, B1_SCK, MSBFIRST); //?
     
                          // rw 0=write, 1=read
  unsigned char command;  // rw a3 a2 a1 a0 n2 n1 n0
  command  = 0x8C;        //  1  0  0  0  1  1  0  0 = читать 4 байта, начиная с первого
                              
  digitalWrite(B1_SCK, LOW);  
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, command);
  digitalWrite(B1_SCK, HIGH);

  pinMode(B3_MISO, INPUT_PULLUP); 
  digitalWrite(B1_SCK, LOW);

  uint8_t xl, xh, yl, yh, calculatedCrc, tleCrc;
  int x, y;  

  xl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  xh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  tleCrc = shiftIn(B3_MISO, B1_SCK, MSBFIRST);

  calculatedCrc = 0xFB;    // пробовал также 0 и FF
  calculatedCrc = MathCRC8(calculatedCrc, xl);
  calculatedCrc = MathCRC8(calculatedCrc, xh);
  calculatedCrc = MathCRC8(calculatedCrc, yl);
  calculatedCrc = MathCRC8(calculatedCrc, yh);        
  calculatedCrc = (~calculatedCrc)&(0b11111111);
 
  digitalWrite(B1_SCK, HIGH);
  digitalWrite(not_chip_select, HIGH);
  if(calculatedCrc == tleCrc) Serial.print("="); else Serial.print("!");
  x = (int)(xl | (xh <<8));
  y = (int)(yl | (yh <<8));
  double angle = atan2((double)y,(double)x) / M_PI * 180 ;
  return angle;
}

uint8_t MathCRC8(uint8_t crc, uint8_t data)
{
  crc ^= data;
  for (uint8_t bit=0 ; bit<8 ; bit++ ) { if ((crc&0b10000000)!=0) { crc <<= 1; crc ^= 0x1D; } else { crc <<= 1; }; };
  return(crc);
};

 

Опубликовано:

Было  кое-что лишнее, убрал, теперь CRC считается (см. ниже).

 

Теперь желательно сделать так, чтобы команду 00000000 отправлять сразу на все датчики. Нет, понятно, что сперва выбрать каждый

digitalWrite(not_chip_select, LOW);

потом отправить эту команду, затем развыбрать все, кроме одного, и оттуда взять x и y. Но не будет ли какой тонкости после этого момента... я довольно плохо понимаю то, что  написано в example2 - в смысле, примечание 3 говорит, что первый deactivated. но не говорит, что второй activated ).

 

А ещё интересно понять, как и можно ли из Raspberry Pi эту штуку подключить ( то бишь, как написать для неё аналог вот этого:

  TCCR1A = 0x23;
  TCCR1B = 0x19;
  TCCR1C = 0x00;
  OCR1A = 3;
  OCR1B = 1;

).

 

//http://avia-sim.ru/forum/viewtopic.php?f=28&t=935&p=31106#p31106

// standard pins used by mmjoy
#define B6_GEN 10
#define B3_MISO 14
#define B1_SCK 15

// two TLE5010 chips selected by B4 and B5
#define NOT_CHIP_SELECT_1 8 //B4 // имя начинается с NOT, потому что выбрано - LOW, не выбрано - HIGH
#define NOT_CHIP_SELECT_2 9 //B5

void setup() {
  unsigned char sreg;
  Serial.begin(9600);

  /* Save global interrupt flag */
  sreg = SREG;
  /* Disable interrupts */
  //__disable_interrupt();
  cli();     
  TCCR1A = 0x23;
  TCCR1B = 0x19;
  TCCR1C = 0x00;
  OCR1A = 3;
  OCR1B = 1;
  /* Restore global interrupt flag */
  SREG = sreg;

  pinMode(B6_GEN, OUTPUT); // B6_GEN 
  pinMode(B3_MISO, OUTPUT); // B3_MISO 
  pinMode(B1_SCK, OUTPUT); // B1_SCK 

  pinMode(NOT_CHIP_SELECT_1, OUTPUT); // select
  pinMode(NOT_CHIP_SELECT_2, OUTPUT); // select

  digitalWrite(NOT_CHIP_SELECT_1, HIGH);
  digitalWrite(NOT_CHIP_SELECT_2, HIGH);

}

void loop() {
  Serial.print(" h ");
  double angle1=tle5010_angle(NOT_CHIP_SELECT_1);
  double angle2=tle5010_angle(NOT_CHIP_SELECT_2);
  Serial.print(round(angle1));
  Serial.print(" ");
  Serial.println(round(angle2));
  delay(200); 
}

double tle5010_angle(int not_chip_select){
  digitalWrite(not_chip_select, LOW); // выбрал устройство
  
  pinMode(B3_MISO, OUTPUT); 
  digitalWrite(B1_SCK, LOW);
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, 0);     // B00000000 - update command!! 

                          // rw 0=write, 1=read
                          // h  h  h  h  l  l  l  l
                          // c  c  c  c  n  n  n  n
  unsigned char command;  // rw a3 a2 a1 a0 n2 n1 n0
  command  = 0x8C;        //  1  0  0  0  1  1  0  0 = читать 4 байта, начиная с первого
  command  = 0b10001100;  //  1  0  0  0  1  1  0  0 = читать 4 байта, начиная с первого
                              
  digitalWrite(B1_SCK, LOW);  
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, command);

  pinMode(B3_MISO, INPUT_PULLUP); 
  digitalWrite(B1_SCK, LOW);

  uint8_t xl, xh, yl, yh, tleCrc;
  int x, y;  

  xl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  xh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  tleCrc = shiftIn(B3_MISO, B1_SCK, MSBFIRST);

  digitalWrite(B1_SCK, HIGH);
  digitalWrite(not_chip_select, HIGH);

  if( checkCrc(xl, xh, yl, yh, tleCrc, (uint8_t)0xFB) ) {
    Serial.print("=");
  } else {
    Serial.print("!");
  }

  x = (int)(xl | (xh <<8));
  y = (int)(yl | (yh <<8));
  double angle = atan2((double)y,(double)x) / M_PI * 180 ;
  return angle;
}

int checkCrc(uint8_t xl, uint8_t xh, uint8_t yl, uint8_t yh, uint8_t tleCrc, uint8_t initialCrc) {
  uint8_t calculatedCrc;
  calculatedCrc = initialCrc;    
  calculatedCrc = MathCRC8(calculatedCrc, xl);
  calculatedCrc = MathCRC8(calculatedCrc, xh);
  calculatedCrc = MathCRC8(calculatedCrc, yl);
  calculatedCrc = MathCRC8(calculatedCrc, yh);        
  calculatedCrc = (~calculatedCrc)&(0b11111111);
  return (calculatedCrc == tleCrc);
}

uint8_t MathCRC8(uint8_t crc, uint8_t data)
{
  crc ^= data;
  for (uint8_t bit=0 ; bit<8 ; bit++ ) { 
    if ((crc & 0b10000000)!=0) { 
      crc <<= 1; 
      crc ^= 0x1D; 
    } else { 
      crc <<= 1; 
    }; 
  };
  return(crc);
};

 

  • Спасибо! 1
  • 4 месяца спустя...
Опубликовано: (изменено)

Я извиняюсь за глупый вопрос, а нельзя ли это сделать стандартной библиотекой SPI? Или это не наши методы?

Изменено пользователем Johnet
Опубликовано:
22.01.2020 в 05:47, Johnet сказал:

Я извиняюсь за глупый вопрос, а нельзя ли это сделать стандартной библиотекой SPI? Или это не наши методы?

Возможно смысл в том, чтобы вешать ноги управления на любые ноги. SPI у TLE-шек не гонится быстрее 2МГц, поэтому битбангом получается не сильно хуже, чем просто SPI.

Ещё момент в том, что так как SPI в полудуплексном режиме, то между отправкой команды и приемом данных надо его перенастраивать на передачу/прием (хотя HAL делает это за нас), а если дергать просто ногами, то назначаешь MOSI выходом с open drain и можно больше не трогать.

  • Спасибо! 2
  • 3 года спустя...
  • 4 месяца спустя...
Опубликовано: (изменено)

Я много вариантов перепробовал, но все никак не моуг получить внятный ответ от TLE5010. Уже даже под нее купил осцилограф. В качестве кода я взял последнюю  опубликованную тут версию. Так же пробовал эксперементировать с SPI ардуино библиотекой, но там тоде безрезультатно.

Сейчас, у меня в окне Serial Monitor только во такое пишется

h !!-135 -135

БУДУ ОЧЕНЬ ПРИЗНАТЕЛЕН ЗА ЛЮБУЮ ПОМОЩЬ/СОВЕТ. Застрял на этот моменте и вот уже несколько месяцев не могу продвинутся вперед.

Контролер - китайский клон Spark Fun Pro Micro. Пробовал еще на Teensy 4.0 \(оригинальном). Через MMJoy вроде сработало, но я хочу сам закодить контроллер, так интерестней. Это в том числе проект для обучения электронике и всему что с ней связано. 

Прикрепляю фото того что сейчас есть


Так выглядят сигналы на MOSI (Желтый) и MISO (Зеленый)

image.thumb.jpeg.9f92ee30c67eb9ad922963a867d246be.jpeg

 

Так выглядят сигналы на SCK (Желтый) и MISO (Зеленый)

image.thumb.jpeg.16ec5b9178b06cb2ef3dc2512338617f.jpeg

 
А вот так выглядят сигналы на  SCK (Желтый) и CS(Зеленый)

image.thumb.jpeg.4bb29a2bffd5cd22bb025a71d76d9371.jpeg

 

Так выглядит сама плата и сигналы к ней по цветам

image.thumb.jpeg.c870c33cbf07cafb81f4283021130aba.jpeg

Сам бредборд в приближении
image.thumb.jpeg.b338cf562795ff02de193779d936b53c.jpeg

Изменено пользователем maxzet
  • Нравится 1
Опубликовано: (изменено)

Подтяжку линии данных не забыл добавить? Среди меня самая распространенная ошибка :)

 

убедись что частота на 5010 у тебя идёт не более 2МГц.

 

Код ногодрыга для вычитывания 5010 публиковал там. Попробуй для начала когда всё под твоим контролем, а потом уже переходи к аппаратному способу.

Что там происходит сказать щас сложно, но работало. Тормоза так считывал чтобы остальные оси не тормозить

https://github.com/l3VGV/bb_spi-tle5010-74hc165

 

Там стм32, но какая разница.

Изменено пользователем l3VGV
Опубликовано: (изменено)

Я выскажу свой ход мыслей, но сразу попрошу меня тапками не закидывать, потому как я только начал постигать этот чудный мир DIY, электроники, хардвер и PCB дизайна. Я до этого много лет занимался прогаммированием, но с электроникой по сути вообще не сталкивался, и сейчас по немногу в нее погружаюсь с нуля. 

Вообщем, я начал с того что наваял по примерам небольшую программку на основе SPI.h библиотеки
 

#include <SPI.h>

#define TLE5010_SS_PIN 10 // Replace with the appropriate SS pin number

void setup() {
  Serial.begin(9600);
  
  // Initialize SPI
  SPI.begin();
  
  // Configure SPI settings
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1));
  
  // Configure SS pin as OUTPUT and set it HIGH initially
  pinMode(TLE5010_SS_PIN, OUTPUT);
  digitalWrite(TLE5010_SS_PIN, HIGH);
  
  // Delay for sensor startup (adjust as needed)
  // delay(1000);
}

void loop() {
  // Enter SPI communication mode with the TLE5010 sensor
  digitalWrite(TLE5010_SS_PIN, LOW);
  // delayMicroseconds(10);
  
  // Send command to read the angle register from the TLE5010 sensor
  int communication = 1 << 7 | 1 << 2 |  2;
  SPI.transfer(communication); // Replace with the appropriate command byte
  
  delayMicroseconds(1);
  // Read the received data
  byte msb = SPI.transfer(0x00);
  byte lsb = SPI.transfer(0x00);
  // delayMicroseconds(10);
  // Exit SPI communication mode with the TLE5010 sensor
  digitalWrite(TLE5010_SS_PIN, HIGH);
  
  // Combine the bytes to form the sensor value
  int sensorValue = (msb << 8) | lsb;
  
  // Print the sensor value
  Serial.print("Sensor Value: ");
  Serial.println(sensorValue, BIN);
  
  delay(10); // Adjust the delay between readings as needed
}


Значения указанные в "SPISettings(4000000, MSBFIRST, SPI_MODE1)" и команду для оправки "int communication = 1 << 7 | 1 << 2 |  2;" я выбирал исходя из просмотра даташитов, которые нашел на просторах интернета (по их выбору инфа ниже). Не исключено, что я что-то не то смотрел или интерпретировал.

Далее я подключил все выходы с TLE5010 к про микро согластно распиновке SPI.

image.thumb.jpeg.ce1f388b5e1ecb8bb660598cd7ef6d77.jpeg

И у меня ничего не сработал. На MISO (пин 14) приходит просто высокий сигнал. Ему вообще никак ни холожно, ни жарко. Он просто выдает при чтении 2 байта со значением 255. Я много ковырял, пробовал, смотрел различные команды, смотрел различные варинты распиновок, различные параметры инициализации, но все тчетно. Пока что я в тупике и пришел за советом/помощью. Хочу доделать вертолетный симулятор, он у меня на пол пути заглох. 
 

Теперь по логике выбора значений для инициализации и формировании кода команды к датчику. Я отыскал вот этот вот даташит, который, как я полагаю описывает датчик TLE5010, в том числе тот китайский, который мне с Алиекспресс пришел.

Собственно, вот тут вроде как указано, что частота синхронизации должна быть строго 4МГц  (4000000)
image.thumb.png.0309bf7e2f8d7c105d6d851a94c4bba2.png
Далее надо указать мод комуникации. В даташите я полался на эту страницу и сравнивал ее с гайдом по модам, который тоже нашел в сети. На сколько я из этого всего понял - комуникаций должна быть SPI_MODE1 (начинается с низкого значения, и чтение идет на спаде)
image.thumb.png.8ca195acb9747bfc6d7a7646b53219e6.png

image.png.29a99adbe8d3fb25dd577514bd9c03ab.png

Далее, опираясь на эти две страницы я взял информацию, что комуникация должна начинаться с наиболее значимого байта (MSBFIRST), и что надо послать байт 0b10000110 (бит 7 указывает, что идет чтение, далее адрес памяти для чтенения - 1, и далее мы говорим, что хотим получить 2 байта -  тоесть XL и XH)
image.thumb.png.f9dbcecbcaf3627fed82436598d7ca47.png

image.thumb.png.2f0cc69ec8b5f230df6a0fab6c2fd23a.png

 

Собственно, на этом месте я и застрял. По MISO не текут никакие данные (смотрел осцилографом). Если надо прислать какие либо результаты чтения с осцилографа - то пишите какие, я пришлю.

 

27.08.2023 в 13:18, l3VGV сказал:

Подтяжку линии данных не забыл добавить? Среди меня самая распространенная ошибка :)

 

убедись что частота на 5010 у тебя идёт не более 2МГц.

 

Я не совсем понимаю что значит коментарий про подтяжку линии данных? и почему частота 2 МГц, если в даташите указана 4МГц. Можешь пояснить?

Изменено пользователем maxzet
Опубликовано: (изменено)
9 часов назад, maxzet сказал:

Я до этого много лет занимался прогаммированием, но с электроникой по сути вообще не сталкивался

 

Электроника хороший доп скил к погромированию. Чо не так сделал - выкидывай плату. Приучает думать прежде чем делать, читать документацию и уважать интерфейсы. Что мы и видем на посте выше.

 

9 часов назад, maxzet сказал:

Я не совсем понимаю что значит коментарий про подтяжку линии данных?

 

У 5010 вход/выход линии данных опен дрейн. Т.е. он может притянуть линию к земле, но не может притянуть к питанию. Т.е. 0 в линию он выдавать может, а 1 не может. 1 получается когда оно отпускает выходом землю. Чтобы это могло произойти, нужно чтобы чтото тянуло линую к питанию, например резистор на 1.5к это достаточное чтото. Вот например на фриджое картинки есть. В даташите это тоже описано.

 

image.png.661437792db9597c488331704fa0446b.png 

 

 

 

9 часов назад, maxzet сказал:

и почему частота 2 МГц, если в даташите указана 4МГц

Если чот не работает на предельных частотах - снижай, всё просто. Частота там указана не как "строго", а как максимальная для некоторого напряжения питания. Если у тебя на ардуине 5В, то можно и 4мега. А если 3.3 то лучше понизить до 2, или ещё меньше.

(в ардуинах не разбираюсь, извините не в курсе какое там питание на какой, с виду не отличаю)

 

 

9 часов назад, maxzet сказал:

По MISO не текут никакие данные (смотрел осцилографом).

 

Значит до штирлица не дошло письмо из центра.

 

Протокол обмена примерно следующий.

 

Сначала посылается дизейбл дивайс(ну вдруг забыл отключить). Т.е. пин CS =1

Потом енабле дейвайс т.е. CS = 0

 

выход м.к. SPI переключается на передачу, т.е. на пуш пул

посылается последовательность байтов 0x00, 0x8C

Выход SPI переключается на прием, т.е. переводится в OpenDrain состояние, иначе 5010 не сможет ничего передать.

Начинается чтение. Формально это делать нужно не сразу а с какойто паузой. Нужно принять 6 байт. 4 байта данных и 2 байта CRC.

 

отпускаем девайс, т.е. делаем ему на пине CS = 1

 

Считаем CRC, выкидываем данные если не совпало. Если слишком много CRC ошибок то или снижай частоты или попробуй понизить значение пулап резистора, но не слишком сильно ато подпалится и м.к. и 5010.

 

 

 

 

 

Изменено пользователем l3VGV
  • Нравится 1
Опубликовано: (изменено)
14 часов назад, l3VGV сказал:

Значит до штирлица не дошло письмо из центра.

 

Протокол обмена примерно следующий.

 

Сначала посылается дизейбл дивайс(ну вдруг забыл отключить). Т.е. пин CS =1

Потом енабле дейвайс т.е. CS = 0

 

выход м.к. SPI переключается на передачу, т.е. на пуш пул

посылается последовательность байтов 0x00,  

Выход SPI переключается на прием, т.е. переводится в OpenDrain состояние, иначе 5010 не сможет ничего передать.

Начинается чтение. Формально это делать нужно не сразу а с какойто паузой. Нужно принять 6 байт. 4 байта данных и 2 байта CRC.

 

отпускаем девайс, т.е. делаем ему на пине CS = 1

 

Считаем CRC, выкидываем данные если не совпало. Если слишком много CRC ошибок то или снижай частоты или попробуй понизить значение пулап резистора, но не слишком сильно ато подпалится и м.к. и 5010.


Вроде все именно так и делаю. Даже смотрю осцилографом на соответствующих каналах, чтобы убедится, что оно действительно передает данные туда куда нужно. 

Сначал падает напражение на CS  и делее передаются 4 байта данных. Вот так выглядят CS (Желтый сигнал) и SCK (зеленый) пины. 1 деление - 2 микросекунды. 1 байт передается ~4 микросекунды (1 бит за 500  наносекунд = 2 МГц)
image.thumb.jpeg.e92e6d6f28bc219f9781c9e1cc04871b.jpeg

 

Далее, я смотрю MOSI канал (желтый), относительно SCK (зеленый). Сначала передается 0x00 (по рекомндации сначала передавать ему ноль), потом передается 0x8c, Потом по MOSI передаются еще 2 нуля (я так понял что так SPI интерфейс читает данные, и по MISO в этот момент времени должны идти данные обратно)
image.thumb.jpeg.3e82111a6e8745b8ad3c51a3748df267.jpeg

Вот второй байт, на меньшей шкале времени (1 деление - 500 наносекунд). Видно, что это SPI_MODE1 - начальное положение 0, считывание предполагается на переходе вниз. 
image.thumb.jpeg.8a5f2eb386a0d7e84336f2582d3ef662.jpeg


Даже убедился, что обмен данными происходит когда CS находится в нуле
image.thumb.jpeg.12f7cbc1e8c4ec03f623bd68d81d90f2.jpeg

 

По MISO всеравно никакие данные не идут. Он просто все время в высоком положении и осилогаф даже его нормально поймать не может (2х каналов видимо мало =( )


image.thumb.jpeg.b7cd744688de153a0dac53f79fc9236c.jpeg

У же думаю что я возможно как то не так использую SPI.h, хотя везде где смотреть, например тут и тут,  чтобы получить по нему данные надо после отсылки команды передать 0 и он тогда должен получить данные. 

byte msb = SPI.transfer(0x00);

Схемы плат, которые мне пришли с китая я не нашел. Могу полько фото их дать. Там стоят уже 1 резистора по 1к и 2 конденсатора, непонятного номинала

image.thumb.jpeg.a7a5b6ea796a7527e5208a09824cdfc9.jpegimage.thumb.jpeg.8f052be754c2534d2627e9a75faaa18e.jpeg


Вообщем, я его и в хвост и в гриву, а он чето вообще ни в какую.

Я уже не понимаю куда смотреть и что еще можно попробовать, чтобы он мне отдал свои данные.

Изменено пользователем maxzet
Опубликовано: (изменено)
2 часа назад, maxzet сказал:

Потом по MOSI передаются еще 2 нуля (я так понял что так SPI интерфейс читает данные

 

тут полудуплексный обмен. в 5010 только 1 линия данных, она и вход и выход. И если твой м.к. не может отключить свой выход на время приема, то конечно там нет ничего. после отсылки 00 и 8с нужно передать микрофон в зал.

Изменено пользователем l3VGV
Опубликовано:

Судя по фотке, это не 0x8C, a 0x86

6screenhantektle5010.png.f4c8d913b4254f58bbcfd43205daf23e.png

После команд (0х00, 0х8С) читаем 5 байт из TLE5010. В этих пяти байтах: 2байта-синус + 2байта-косинус + 1байт-CRC.

Обратите внимание на необходимость развязки MOSI и MISO на плате Pro Micro. Чтобы вывод MOSI не давил данные на выводе MISO при приеме из TLE5010.

Или пользуйтесь битбэнгом (ногодрыг).

  • Нравится 2
Опубликовано:
29.08.2023 в 00:01, maxzet сказал:

и команду для оправки "int communication = 1 << 7 | 1 << 2 |  2;" я выбирал исходя из просмотра даташитов

Неправильно.

Правильно будет так:

int communication = 0x8C;

И еще не вижу конфигурации микроконтроллера для генерации тактовой частоты 4МГц для TLE5010

Опубликовано:
1 час назад, Komaroff сказал:

Судя по фотке

 

а я всегда говорил: логические анализаторы - для слабых духом!!!

Опубликовано: (изменено)

Я решил за реверс энжинирить как эта камуникация работает у MMJoy. Подключил все, нашел MCU Port  и начал смотреть осцилографом.

Первое что я обнаружил - что по MOSI течет сигнал генератора часототой в 4 МГц (за 1 милисекунду успевает 4 такта проскочить). А я по MOSI пускал саму дату. По крайней мере теперь понятно почему в некоторых версиях китайского кита TLE5010 этот пин обозрачают как GEN

image.thumb.jpeg.ba5dede14c8329168a781c013d457f5b.jpeg


Далее - сам обмен  данных течет по MISO. Причем данные команды и данные ответа текут с разной частотой. Сначала с частотой 1 МГц отдается пустая команда (0x00), следом за ней летит 0x8C (0b10001100). Потом возвращаются 5 байт с частотой 2 МГц. SCK - определяет частоту передачи данных. 
image.thumb.jpeg.3e9fe0ddb12895d44097087fef940941.jpegimage.thumb.jpeg.d96d8e91fe86215331981fa764f70dcf.jpeg


Тут я видимо криво прочел мануал - последине 3 бита указывают сколько байт передать и начиная с какого регистра передавать. Нас интересуют биты XL, XH, YL, YH (со страницы даташита Register manual приведенной выше).
 

Далее, вариант передачи, я так правильно понял, что это все-таки MODE1 (из таблицы приведенной выше), и я все-таки его правильно определил по даташиту
image.thumb.jpeg.7ce8c05f9d605920d9eaaa9130338232.jpeg

 

Из остальных вещей на что упал глаз:
Распиновка получается такая - на 10 пин (MOSI/GEN на TLE5010 плате) выходит генератор в 4МГц, он непрерывен. Данные передаются в зад и вперед по 14 пину (он же MISO на плате). 15ый пин (он же SCK на плате) служит для синхронизации передачи данных, и скачет с 1 МГц для команды до 2МГц для данных. Ну и пин A2 определяет плату к которой обращаются (он выходит на CS).

Так же CS почти сразу уходит на ноль с началом передачи данных
image.thumb.jpeg.3dd8e41f5981275514c94e1fbaaf0a17.jpeg

 

И SCK падает вниз за 8мс до начала передачи первого байта (0x00)
image.thumb.jpeg.6d4d525539ab825d5dd53db5fd62c049.jpeg

Вообщем-то завтра буду пробовать воплощать в код все найденное. Меня очень сильно ввело в заблуждение обозначение MOSI на плате, и я полагала, что по нему надо передавать команду, а по MISO ее получать (поверил что их названия отображают их суть).
 

30.08.2023 в 10:04, Komaroff сказал:

Неправильно.

Правильно будет так:

int communication = 0x8C;

И еще не вижу конфигурации микроконтроллера для генерации тактовой частоты 4МГц для TLE5010

Да, верно. Я не так даташит прочел. Это тоже поправлю. Спасибо!

Изменено пользователем maxzet
  • 2 недели спустя...
Опубликовано: (изменено)

По результатам всех обсуждений у меня получилась вот такая вот схема. Хочу ее выложить тут для критики и указаний на возможные ошибки прежде, чем оправлять на печать в китай. Все-таки ждать месяц, и лучше чтобы дополнительные перепроверки были, от людей кто в этом понимает больше меня.

Тут 2 оси X и Y и 23 кнопки, подключеные через цепочку сдвиговых регистров.

Собственно, схема
image.thumb.png.ee6dd37c0e377712d7525d77a855715d.png

 

С1 - это будет 100микрофарадный конденсатор (а не 22 как указано на картинке, другой емкости с нужным футпринтом во фьюжен360 не нашел). Он был указан в схеме, найденной мной в сети для подключения 74hc165. Я не свовсем понимаю зачем он там. В статье это упоминается в скольз как "хорошая идея". Если ктото пояснит, буду благодарен.

X и Y оси - это подключение TLE5010 (китайски кит с алиэкспресс). Пин 1 - это GEN (он же MOSI), пин 6 - VCC.


Кнопки: 24ый пин  - это VCC. Он общий на все кнопки и при нажатии сигнал будет приходить на один из 23ех других пинов.

Резисторы  - 0402 сопротивлением 10кОм (тоже с алиэкспресс).

Вот код для Ардуино, который у меня сейчас. Либу для джостика я пока что в нее не включал.  Собственно это самая крайняя версия кода указнного в этой теме для подключения TLE5010 (и вывод крайних и центрального положений) + подключение 74hc165.
 

//http://avia-sim.ru/forum/viewtopic.php?f=28&t=935&p=31106#p31106

// standard pins used by mmjoy
#define B6_GEN 10
#define B3_MISO 14
#define B1_SCK 15

// two TLE5010 chips selected by B4 and B5
#define NOT_CHIP_SELECT_1 8 //B4 // имя начинается с NOT, потому что выбрано - LOW, не выбрано - HIGH
#define NOT_CHIP_SELECT_2 9 //B5
#define NOT_CHIP_SELECT_3 7 //B5

#define LOAD 5
#define DATAIN 4
#define CLOCKIN 3

double lowest = 0;
double highest = 0;
double middle = 0;

void setup() {
  unsigned char sreg;
  Serial.begin(9600);

  /* Save global interrupt flag */
  sreg = SREG;
  /* Disable interrupts */
  //__disable_interrupt();
  cli();     
  TCCR1A = 0x23;
  TCCR1B = 0x19;
  TCCR1C = 0x00;
  OCR1A = 3;
  OCR1B = 1;
  /* Restore global interrupt flag */
  SREG = sreg;

  pinMode(B6_GEN, OUTPUT); // B6_GEN 
  pinMode(B3_MISO, OUTPUT); // B3_MISO 
  pinMode(B1_SCK, OUTPUT); // B1_SCK 

  pinMode(NOT_CHIP_SELECT_1, OUTPUT); // select
  pinMode(NOT_CHIP_SELECT_2, OUTPUT); // select
  pinMode(NOT_CHIP_SELECT_3, OUTPUT); // select

  digitalWrite(NOT_CHIP_SELECT_1, HIGH);
  digitalWrite(NOT_CHIP_SELECT_2, HIGH);
  digitalWrite(NOT_CHIP_SELECT_3, HIGH);

  // Setup 74HC165 connections
  pinMode(LOAD, OUTPUT);
  pinMode(CLOCKIN, OUTPUT); // Clock in
  pinMode(DATAIN, INPUT); // Data in
}

void loop() {
  Serial.print(" h ");
  double angle1=tle5010_angle(NOT_CHIP_SELECT_1);
  double angle2=tle5010_angle(NOT_CHIP_SELECT_2);

  if (lowest == 0) lowest = angle1;
  if (lowest > angle1) lowest = angle1;

  if (highest == 0) highest = angle1;
  if (highest < angle1) highest = angle1;
  middle = (highest+lowest)/2;

  Serial.print(angle1);
  Serial.print(" ");
  Serial.print(angle2);
  Serial.print(", lowest: ");
  Serial.print(lowest);
  Serial.print(", highest: ");
  Serial.print(highest);
  Serial.print(", diff: ");
  Serial.print(highest-lowest);
  Serial.print(", middle: ");
  Serial.print(middle);
  Serial.print(", deviation: ");
  Serial.println(middle-angle1);
  // delayMicroseconds(20); 

  // Print to serial monitor
  Serial.print("Pin States: ");
  byte incoming= chip_74hc165_state(NOT_CHIP_SELECT_3);
  delay(150);
}

double tle5010_angle(int not_chip_select){
  digitalWrite(not_chip_select, LOW); // выбрал устройство
  
  pinMode(B3_MISO, OUTPUT); 
  digitalWrite(B1_SCK, LOW);
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, 0);     // B00000000 - update command!! 

                          // rw 0=write, 1=read
                          // h  h  h  h  l  l  l  l
                          // c  c  c  c  n  n  n  n
  unsigned char command;  // rw a3 a2 a1 a0 n2 n1 n0
  command  = 0x8C;        //  1  0  0  0  1  1  0  0 = читать 4 байта, начиная с первого
  command  = 0b10001100;  //  1  0  0  0  1  1  0  0 = читать 4 байта, начиная с первого
                              
  digitalWrite(B1_SCK, LOW);  
  shiftOut(B3_MISO, B1_SCK, MSBFIRST, command);

  pinMode(B3_MISO, INPUT_PULLUP); 
  digitalWrite(B1_SCK, LOW);

  uint8_t xl, xh, yl, yh, tleCrc;
  int x, y;  

  xl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  xh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yl     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  yh     = shiftIn(B3_MISO, B1_SCK, MSBFIRST);
  tleCrc = shiftIn(B3_MISO, B1_SCK, MSBFIRST);

  digitalWrite(B1_SCK, HIGH);
  digitalWrite(not_chip_select, HIGH);

  if( checkCrc(xl, xh, yl, yh, tleCrc, (uint8_t)0xFB) ) {
    Serial.print("=");
  } else {
    Serial.print("!");
  }

  x = (int)(xl | (xh <<8));
  y = (int)(yl | (yh <<8));
  double angle = atan2((double)y,(double)x) / M_PI * 180 ;
  return angle;
}

int checkCrc(uint8_t xl, uint8_t xh, uint8_t yl, uint8_t yh, uint8_t tleCrc, uint8_t initialCrc) {
  uint8_t calculatedCrc;
  calculatedCrc = initialCrc;    
  calculatedCrc = MathCRC8(calculatedCrc, xl);
  calculatedCrc = MathCRC8(calculatedCrc, xh);
  calculatedCrc = MathCRC8(calculatedCrc, yl);
  calculatedCrc = MathCRC8(calculatedCrc, yh);        
  calculatedCrc = (~calculatedCrc)&(0b11111111);
  return (calculatedCrc == tleCrc);
}

uint8_t MathCRC8(uint8_t crc, uint8_t data)
{
  crc ^= data;
  for (uint8_t bit=0 ; bit<8 ; bit++ ) { 
    if ((crc & 0b10000000)!=0) { 
      crc <<= 1; 
      crc ^= 0x1D; 
    } else { 
      crc <<= 1; 
    }; 
  };
  return(crc);
};

byte chip_74hc165_state(int not_chip_select) {
  // // Get data from 74HC165
  digitalWrite(not_chip_select, LOW);
  delayMicroseconds(2);

  // Write pulse to load pin
  digitalWrite(LOAD, LOW);
  delayMicroseconds(5);
  // digitalWrite(LOAD, HIGH);

  byte value1 = 0;
  for (int i = 0; i < 8; ++i) {
    digitalWrite(CLOCKIN, HIGH);
    delayMicroseconds(2);  // Optional: Adjust this delay if needed
    value1 |= digitalRead(DATAIN) << (7 - i);
    if (i==0) digitalWrite(LOAD, HIGH); // We disable LOAD after the first bit is received
    digitalWrite(CLOCKIN, LOW);
    delayMicroseconds(2);
  }

  byte value2 = 0;
  for (int i = 0; i < 8; ++i) {
    digitalWrite(CLOCKIN, HIGH);
    delayMicroseconds(2);  // Optional: Adjust this delay if needed
    value2 |= digitalRead(DATAIN) << (7 - i);
    digitalWrite(CLOCKIN, LOW);
    delayMicroseconds(2);
  }
  
  byte value3 = 0;
  for (int i = 0; i < 8; ++i) {
    digitalWrite(CLOCKIN, HIGH);
    delayMicroseconds(2);  // Optional: Adjust this delay if needed
    value2 |= digitalRead(DATAIN) << (7 - i);
    digitalWrite(CLOCKIN, LOW);
    delayMicroseconds(2);
  }

  Serial.print(value1, BIN);
  Serial.print(value2, BIN);
  Serial.println(value3, BIN);

  digitalWrite(not_chip_select, HIGH);

  return value1;
}


Я спецально перевожу LOAD после получения первого байта, потому что иначе самый первый байт теряется при передаче. По крайней мере я так понял глядя на работу 74hc165 через осциограф. 

Буду благодарен за любую критику или рекомендации по улучшению.

Изменено пользователем maxzet

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас
×
×
  • Создать...