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
Рекомендованные сообщения
Создайте аккаунт или войдите в него для комментирования
Вы должны быть пользователем, чтобы оставить комментарий
Создать аккаунт
Зарегистрируйтесь для получения аккаунта. Это просто!
Зарегистрировать аккаунтВойти
Уже зарегистрированы? Войдите здесь.
Войти сейчас