vvm13ru Опубликовано: 18 сентября 2019 Опубликовано: 18 сентября 2019 Как минимум два человека (кроме меня) заинтересованы этой темой. Хорошо иметь возможность писать какой-то свой код, а не быть привязанным к 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; }
=VIRPIL=mega_mozg_13 Опубликовано: 19 сентября 2019 Опубликовано: 19 сентября 2019 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
vvm13ru Опубликовано: 19 сентября 2019 Автор Опубликовано: 19 сентября 2019 Спасибо. Что-то 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); };
vvm13ru Опубликовано: 20 сентября 2019 Автор Опубликовано: 20 сентября 2019 Было кое-что лишнее, убрал, теперь 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
Johnet Опубликовано: 22 января 2020 Опубликовано: 22 января 2020 (изменено) Я извиняюсь за глупый вопрос, а нельзя ли это сделать стандартной библиотекой SPI? Или это не наши методы? Изменено 22 января 2020 пользователем Johnet
WG_Magners Опубликовано: 29 января 2020 Опубликовано: 29 января 2020 22.01.2020 в 05:47, Johnet сказал: Я извиняюсь за глупый вопрос, а нельзя ли это сделать стандартной библиотекой SPI? Или это не наши методы? Возможно смысл в том, чтобы вешать ноги управления на любые ноги. SPI у TLE-шек не гонится быстрее 2МГц, поэтому битбангом получается не сильно хуже, чем просто SPI. Ещё момент в том, что так как SPI в полудуплексном режиме, то между отправкой команды и приемом данных надо его перенастраивать на передачу/прием (хотя HAL делает это за нас), а если дергать просто ногами, то назначаешь MOSI выходом с open drain и можно больше не трогать. 2
Donatello-y Опубликовано: 22 апреля 2023 Опубликовано: 22 апреля 2023 Купил я tle5010 там вместо gen MOSI, сеч из темы нули выдает.
maxzet Опубликовано: 26 августа 2023 Опубликовано: 26 августа 2023 (изменено) Я много вариантов перепробовал, но все никак не моуг получить внятный ответ от TLE5010. Уже даже под нее купил осцилограф. В качестве кода я взял последнюю опубликованную тут версию. Так же пробовал эксперементировать с SPI ардуино библиотекой, но там тоде безрезультатно. Сейчас, у меня в окне Serial Monitor только во такое пишется h !!-135 -135 БУДУ ОЧЕНЬ ПРИЗНАТЕЛЕН ЗА ЛЮБУЮ ПОМОЩЬ/СОВЕТ. Застрял на этот моменте и вот уже несколько месяцев не могу продвинутся вперед. Контролер - китайский клон Spark Fun Pro Micro. Пробовал еще на Teensy 4.0 \(оригинальном). Через MMJoy вроде сработало, но я хочу сам закодить контроллер, так интерестней. Это в том числе проект для обучения электронике и всему что с ней связано. Прикрепляю фото того что сейчас есть Так выглядят сигналы на MOSI (Желтый) и MISO (Зеленый) Так выглядят сигналы на SCK (Желтый) и MISO (Зеленый) А вот так выглядят сигналы на SCK (Желтый) и CS(Зеленый) Так выглядит сама плата и сигналы к ней по цветам Сам бредборд в приближении Изменено 26 августа 2023 пользователем maxzet 1
l3VGV Опубликовано: 27 августа 2023 Опубликовано: 27 августа 2023 (изменено) Подтяжку линии данных не забыл добавить? Среди меня самая распространенная ошибка убедись что частота на 5010 у тебя идёт не более 2МГц. Код ногодрыга для вычитывания 5010 публиковал там. Попробуй для начала когда всё под твоим контролем, а потом уже переходи к аппаратному способу. Что там происходит сказать щас сложно, но работало. Тормоза так считывал чтобы остальные оси не тормозить https://github.com/l3VGV/bb_spi-tle5010-74hc165 Там стм32, но какая разница. Изменено 27 августа 2023 пользователем l3VGV
maxzet Опубликовано: 28 августа 2023 Опубликовано: 28 августа 2023 (изменено) Я выскажу свой ход мыслей, но сразу попрошу меня тапками не закидывать, потому как я только начал постигать этот чудный мир 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. И у меня ничего не сработал. На MISO (пин 14) приходит просто высокий сигнал. Ему вообще никак ни холожно, ни жарко. Он просто выдает при чтении 2 байта со значением 255. Я много ковырял, пробовал, смотрел различные команды, смотрел различные варинты распиновок, различные параметры инициализации, но все тчетно. Пока что я в тупике и пришел за советом/помощью. Хочу доделать вертолетный симулятор, он у меня на пол пути заглох. Теперь по логике выбора значений для инициализации и формировании кода команды к датчику. Я отыскал вот этот вот даташит, который, как я полагаю описывает датчик TLE5010, в том числе тот китайский, который мне с Алиекспресс пришел. Собственно, вот тут вроде как указано, что частота синхронизации должна быть строго 4МГц (4000000) Далее надо указать мод комуникации. В даташите я полался на эту страницу и сравнивал ее с гайдом по модам, который тоже нашел в сети. На сколько я из этого всего понял - комуникаций должна быть SPI_MODE1 (начинается с низкого значения, и чтение идет на спаде) Далее, опираясь на эти две страницы я взял информацию, что комуникация должна начинаться с наиболее значимого байта (MSBFIRST), и что надо послать байт 0b10000110 (бит 7 указывает, что идет чтение, далее адрес памяти для чтенения - 1, и далее мы говорим, что хотим получить 2 байта - тоесть XL и XH) Собственно, на этом месте я и застрял. По MISO не текут никакие данные (смотрел осцилографом). Если надо прислать какие либо результаты чтения с осцилографа - то пишите какие, я пришлю. 27.08.2023 в 13:18, l3VGV сказал: Подтяжку линии данных не забыл добавить? Среди меня самая распространенная ошибка убедись что частота на 5010 у тебя идёт не более 2МГц. Я не совсем понимаю что значит коментарий про подтяжку линии данных? и почему частота 2 МГц, если в даташите указана 4МГц. Можешь пояснить? Изменено 28 августа 2023 пользователем maxzet
l3VGV Опубликовано: 29 августа 2023 Опубликовано: 29 августа 2023 (изменено) 9 часов назад, maxzet сказал: Я до этого много лет занимался прогаммированием, но с электроникой по сути вообще не сталкивался Электроника хороший доп скил к погромированию. Чо не так сделал - выкидывай плату. Приучает думать прежде чем делать, читать документацию и уважать интерфейсы. Что мы и видем на посте выше. 9 часов назад, maxzet сказал: Я не совсем понимаю что значит коментарий про подтяжку линии данных? У 5010 вход/выход линии данных опен дрейн. Т.е. он может притянуть линию к земле, но не может притянуть к питанию. Т.е. 0 в линию он выдавать может, а 1 не может. 1 получается когда оно отпускает выходом землю. Чтобы это могло произойти, нужно чтобы чтото тянуло линую к питанию, например резистор на 1.5к это достаточное чтото. Вот например на фриджое картинки есть. В даташите это тоже описано. 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. Изменено 29 августа 2023 пользователем l3VGV 1
maxzet Опубликовано: 29 августа 2023 Опубликовано: 29 августа 2023 (изменено) 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 МГц) Далее, я смотрю MOSI канал (желтый), относительно SCK (зеленый). Сначала передается 0x00 (по рекомндации сначала передавать ему ноль), потом передается 0x8c, Потом по MOSI передаются еще 2 нуля (я так понял что так SPI интерфейс читает данные, и по MISO в этот момент времени должны идти данные обратно) Вот второй байт, на меньшей шкале времени (1 деление - 500 наносекунд). Видно, что это SPI_MODE1 - начальное положение 0, считывание предполагается на переходе вниз. Даже убедился, что обмен данными происходит когда CS находится в нуле По MISO всеравно никакие данные не идут. Он просто все время в высоком положении и осилогаф даже его нормально поймать не может (2х каналов видимо мало =( ) У же думаю что я возможно как то не так использую SPI.h, хотя везде где смотреть, например тут и тут, чтобы получить по нему данные надо после отсылки команды передать 0 и он тогда должен получить данные. byte msb = SPI.transfer(0x00); Схемы плат, которые мне пришли с китая я не нашел. Могу полько фото их дать. Там стоят уже 1 резистора по 1к и 2 конденсатора, непонятного номинала Вообщем, я его и в хвост и в гриву, а он чето вообще ни в какую. Я уже не понимаю куда смотреть и что еще можно попробовать, чтобы он мне отдал свои данные. Изменено 29 августа 2023 пользователем maxzet
l3VGV Опубликовано: 29 августа 2023 Опубликовано: 29 августа 2023 (изменено) 2 часа назад, maxzet сказал: Потом по MOSI передаются еще 2 нуля (я так понял что так SPI интерфейс читает данные тут полудуплексный обмен. в 5010 только 1 линия данных, она и вход и выход. И если твой м.к. не может отключить свой выход на время приема, то конечно там нет ничего. после отсылки 00 и 8с нужно передать микрофон в зал. Изменено 29 августа 2023 пользователем l3VGV
Komaroff Опубликовано: 30 августа 2023 Опубликовано: 30 августа 2023 Судя по фотке, это не 0x8C, a 0x86 6 После команд (0х00, 0х8С) читаем 5 байт из TLE5010. В этих пяти байтах: 2байта-синус + 2байта-косинус + 1байт-CRC. Обратите внимание на необходимость развязки MOSI и MISO на плате Pro Micro. Чтобы вывод MOSI не давил данные на выводе MISO при приеме из TLE5010. Или пользуйтесь битбэнгом (ногодрыг). 2
Komaroff Опубликовано: 30 августа 2023 Опубликовано: 30 августа 2023 29.08.2023 в 00:01, maxzet сказал: и команду для оправки "int communication = 1 << 7 | 1 << 2 | 2;" я выбирал исходя из просмотра даташитов Неправильно. Правильно будет так: int communication = 0x8C; И еще не вижу конфигурации микроконтроллера для генерации тактовой частоты 4МГц для TLE5010
l3VGV Опубликовано: 30 августа 2023 Опубликовано: 30 августа 2023 1 час назад, Komaroff сказал: Судя по фотке а я всегда говорил: логические анализаторы - для слабых духом!!!
maxzet Опубликовано: 31 августа 2023 Опубликовано: 31 августа 2023 (изменено) Я решил за реверс энжинирить как эта камуникация работает у MMJoy. Подключил все, нашел MCU Port и начал смотреть осцилографом. Первое что я обнаружил - что по MOSI течет сигнал генератора часототой в 4 МГц (за 1 милисекунду успевает 4 такта проскочить). А я по MOSI пускал саму дату. По крайней мере теперь понятно почему в некоторых версиях китайского кита TLE5010 этот пин обозрачают как GEN Далее - сам обмен данных течет по MISO. Причем данные команды и данные ответа текут с разной частотой. Сначала с частотой 1 МГц отдается пустая команда (0x00), следом за ней летит 0x8C (0b10001100). Потом возвращаются 5 байт с частотой 2 МГц. SCK - определяет частоту передачи данных. Тут я видимо криво прочел мануал - последине 3 бита указывают сколько байт передать и начиная с какого регистра передавать. Нас интересуют биты XL, XH, YL, YH (со страницы даташита Register manual приведенной выше). Далее, вариант передачи, я так правильно понял, что это все-таки MODE1 (из таблицы приведенной выше), и я все-таки его правильно определил по даташиту Из остальных вещей на что упал глаз: Распиновка получается такая - на 10 пин (MOSI/GEN на TLE5010 плате) выходит генератор в 4МГц, он непрерывен. Данные передаются в зад и вперед по 14 пину (он же MISO на плате). 15ый пин (он же SCK на плате) служит для синхронизации передачи данных, и скачет с 1 МГц для команды до 2МГц для данных. Ну и пин A2 определяет плату к которой обращаются (он выходит на CS). Так же CS почти сразу уходит на ноль с началом передачи данных И SCK падает вниз за 8мс до начала передачи первого байта (0x00) Вообщем-то завтра буду пробовать воплощать в код все найденное. Меня очень сильно ввело в заблуждение обозначение MOSI на плате, и я полагала, что по нему надо передавать команду, а по MISO ее получать (поверил что их названия отображают их суть). 30.08.2023 в 10:04, Komaroff сказал: Неправильно. Правильно будет так: int communication = 0x8C; И еще не вижу конфигурации микроконтроллера для генерации тактовой частоты 4МГц для TLE5010 Да, верно. Я не так даташит прочел. Это тоже поправлю. Спасибо! Изменено 31 августа 2023 пользователем maxzet
maxzet Опубликовано: 11 сентября 2023 Опубликовано: 11 сентября 2023 (изменено) По результатам всех обсуждений у меня получилась вот такая вот схема. Хочу ее выложить тут для критики и указаний на возможные ошибки прежде, чем оправлять на печать в китай. Все-таки ждать месяц, и лучше чтобы дополнительные перепроверки были, от людей кто в этом понимает больше меня. Тут 2 оси X и Y и 23 кнопки, подключеные через цепочку сдвиговых регистров. Собственно, схема С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 через осциограф. Буду благодарен за любую критику или рекомендации по улучшению. Изменено 11 сентября 2023 пользователем maxzet
Рекомендованные сообщения
Пожалуйста, войдите для комментирования
Вы сможете оставить комментарий после входа
Войти сейчас