controller_m30 1 14 мая, 2020 Опубликовано 14 мая, 2020 · Жалоба Ещё такое соображение. Есть две команды UCB1CTLW1 = UCASTP_2; // automatic stop assertion UCB1TBCNT = 1; // TX only 1 byte of data Это счётчик автогенерации сигнала STOP, а значение UCASTP_2 разрешает его работу. Т.е. в данной программе сигнал STOP вырабатывается автоматически (скорее всего). В документации на модуль I2C этого контроллера пишут, что при использовании авто-STOP только с одним байтом, не надо устанавливать STOP из программы. Документ slau445i (стр.637) Цитата When UCASTPx = 10 is set, the byte counter is used for STOP generation and the user does not need to set the UCTXSTP. This is recommended when transmitting only one byte. Почему именно для одного байта, хз. Но это даже выделено в тексте... Может установка STOP в обработчике приёма байта, что-то там сбивает в этом механизме? Закомментируйте её для пробы (и заодно узнаем, работает ли авто-STOP). Или закомментить саму инициализацию авто-STOP. Посмотреть что получится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 14 мая, 2020 Опубликовано 14 мая, 2020 · Жалоба Спасибо, вроде дошло. Я думал, что правильно - подавать команду на формирование STOP после чтения приёмного буфера, чтобы приём не прервался. В итоге эта команда проходила с опозданием, уже во время следующей записи, прерывая её сразу после отправки адреса. Оказалось, что скомандовать "отправить STOP" можно (и нужно) уже после того, как прошёл START (то есть сбросился флаг UCTXSTT). Тогда приёмник выполнит всё, что требуется: и адрес слейва передаст, и ответ в буфер примет. 51 minutes ago, controller_m30 said: Это счётчик автогенерации сигнала STOP, а значение UCASTP_2 разрешает его работу. Т.е. в данной программе сигнал STOP вырабатывается автоматически (скорее всего). В документации на модуль I2C этого контроллера пишут, что при использовании авто-STOP только с одним байтом, не надо устанавливать STOP из программы. Документ slau445i (стр.637) Почему именно для одного байта, хз. Но это даже выделено в тексте... Автоматически STOP вырабатывается только в режиме записи, у меня так и происходит. Не пробовал пока, будет ли работать с более чем одним байтом данных. Должен, по идее, на то и счётчик передаваемых байтов UCB1TBCNT. При чтении же нужно STOP посылать самому. Хотя, проверить ещё надо. Однако, если на запись счётчик передаваемых байтов есть, то такого на принимаемые байты нет, поэтому приёмник и не может автоматом генерировать STOP, как я понимаю. 18 hours ago, Сергей Борщ said: И еще один момент: после получения последнего байта ведущий должен выставить на шину NAK вместо ACK. Это заставит ведомого прекратить выдавать биты на шину и позволит ведущему сформировать STOP или повторный START после окончания NACK (в противном случае ведомый начнет в этом месте выдавать первый бит следующего байта, который может оказаться нулем и не позволит сформировать STOP или START). При беглом просмотре вашего кода из первого сообщения никаких упоминаний NACK я не увидел. Спасибо, хорошее замечание. Но сейчас у меня NACK и так автоматически отсылается пред СТОП-ом в режиме чтения. Возможно, как раз потому, что я принудительно отправляю команду STOP до чтения буфера. Quote A STOP condition is either generated by the automatic STOP generation or by setting the UCTXSTP bit. The next byte received from the slave is followed by a NACK and a STOP condition. This NACK occurs immediately if the eUSCI_B module is currently waiting for UCBxRXBUF to be read. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 19 мая, 2020 Опубликовано 19 мая, 2020 · Жалоба Ещё парадокс. Модуль eUSCI_B у меня тактируется от SMCLK, коэффициент деления в регистре UCB1BRW выставлен 8. То есть, частота BRCLK (она же SMCLK) должна быть, по идее, в восемь раз выше, чем SCL. Clock System Block настроен на использование DCO, его частота (по умолчанию) - 8MHz. Биты DIVM и DIVS в регистре SLCTL5 установлены в 0, то есть коэффициент деления = 1. Однако, при этих условиях частоту SCL на шине I2C я получаю равной 132кГц. Больше того, если я меняю частоту DCO (больше ничего) от 1 до 24MHz, то выходит такая зависимость: Здесь в первой колонке - частота DCO, во второй - измеренная SCL, в третьей - рассчитанная SMCLK (SCL x8), а в четвёртой - коэффициент деления основной частоты (DCO), чтобы получить такую SMCLK (условно DIVM, который должен быть =1, или хотя бы константой). Странно это. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
controller_m30 1 19 мая, 2020 Опубликовано 19 мая, 2020 (изменено) · Жалоба Мне кажется, в предыдущих моделях, DCO было настроено по умолчанию на 1MHz (или на 2MHz). Может и в этой традицию сохранили. Если по умолчанию 1MHz, то после деления на 8 как раз получается что-то близкое к 132KHz. Надо это как-то проверить. Для удобства, в некоторых моделях можно вывести сигналы MCLK, SMCLK, ACLK прямо на пины ввода-вывода (это на распиновке микросхемы есть, среди кучи остальных функций) В этой модели, MCLK можно вывести на P2.6; P3.0. Какие настройки пинов сделать чтоб вывести MCLK, приведено в документе на стр.98 (для P2.6), и стр.100 (для P3.0). Спойлер Регистр PxSEL указанный в таблицах, на самом деле состоит из двух регистров, PxSEL0 и PxSEL1. В первом содержится младший бит, а во втором старший бит. Вместе они образуют двухбитовое значение альтернативной функции для каждого пина. Подробно про это на стр.314 документ slau445i И для остальных сигналов: SMCLK - P1.0; P3.4 ACLK - P1.1 Изменено 19 мая, 2020 пользователем controller_m30 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 19 мая, 2020 Опубликовано 19 мая, 2020 · Жалоба 18 часов назад, Herz сказал: Clock System Block настроен на использование DCO, его частота (по умолчанию) - 8MHz. Биты DIVM и DIVS в регистре SLCTL5 установлены в 0, то есть коэффициент деления = 1. Однако, при этих условиях частоту SCL на шине I2C я получаю равной 132кГц. Почитал описание системы тактирования на MSP430FR2355 - мозг начал сворачиваться в трубочку Написано так, что и 100 граммов будет мало. Написано следующее:After PUC, DCO locked by FLL operation with XT1CLK is selected by default. The FLL stabilizes MCLK and SMCLK to 1 MHz and fDCOCLKDIV = 1 MHz однако дальше:By default, the crystal pins (XT1IN, XT1OUT) are shared with general-purpose I/Os. To enable XT1, the PSEL bits И каким образом MCLK будет 1 MHz, если DCO по умолчанию управляется FLL, которая должна тактироваться от XT1, но который по умолчанию отключен? Читаем дальше:If XT1 is used but does not work properly, fault protection logic forces REFO as the FLL reference clock. Т.е. происходит следующее (ИМХО, что там на самом деле, не знаю ): Кварца нет, да и он после рестарта выключен. Тактирование переключается на REFO = 32768 Hz Дальше на FLL c параметрами FLLD = 1 (/2) и FLLN = 31 (х32). Получаем fDCOCLK = 32.768 х 32 х 2 = 2.097152 MHz fDCOCLKDIV = 1.048576 MHz Потом делите на 8 и получаете 131 кГц Ну а когда начинаете менять частоту DCO, тут вааще непонятно что происходит и как это у них работает, т.к. пока DCO контролируется FLL, и чтобы переключить его на ручное управление, нужно:By default, FLL operation is enabled. FLL operation can be disabled by setting SCG0 or SCG1. When the FLL is disabled, the DCO continues to operate at the current settings defined in CSCTL0 and CSCTL1. The DCO frequency can be adjusted manually if desired. Otherwise, the DCO frequency is stabilized by the FLL operation. С непривычки просто мрак Пойду я лучше в CubeMX галочек понаставлю и буду на диване валяться... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 71 19 мая, 2020 Опубликовано 19 мая, 2020 · Жалоба 26 minutes ago, Baser said: Ну а когда начинаете менять частоту DCO, тут вааще непонятно что происходит и как это у них работает, т.к. пока DCO контролируется FLL, и чтобы переключить его на ручное управление, нужно:By default, FLL operation is enabled. FLL operation can be disabled by setting SCG0 or SCG1. When the FLL is disabled, the DCO continues to operate at the current settings defined in CSCTL0 and CSCTL1. The DCO frequency can be adjusted manually if desired. Otherwise, the DCO frequency is stabilized by the FLL operation. С непривычки просто мрак Поиду я лучше в CubeMX галочек понаставлю и пойду на диване валяться... раньше (в F1,F2,G2,...) DCO был вообще без FLL, и его частота просто определялась через CSCTL0 and CSCTL1, а теперь при включенном FLL он опирается либо на кварц либо на RC, и соответственно для изменения частоты менять надо множители FLL, а он уже будет подстраивать DCO. параллельно с FLL руками туда лазить не надо. для смены частоты надо крутить множитель FLLN в CSCTL2, а Herz насколько я понял менял DCORSEL, который не совсем меняет частоту, а задаёт диапазон (DCORSEL=24МГц лишь значит что частота может быть в диапазоне от 12 до 45МГц :)), Figure 5-6. Typical DCO Frequency из даташита, но только когда FLL отключен. соответственно FLL от такого обращения (когда кто-то его генератору параллельно режимы меняет пока он пытается частоту удержать) скорее всего дурел и какую попало частоту выдавал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 20 мая, 2020 Опубликовано 20 мая, 2020 · Жалоба Да, похоже, я недооценил сложность процедуры смены частоты, хоть в документации так бодро заявлено: Quote The CS module can be configured or reconfigured by software at any time during program execution. Quote The DCO frequency can be adjusted by software using the DCORSEL, DCO, and MOD bits. Придётся покопать глубже. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gosha-z 2 20 мая, 2020 Опубликовано 20 мая, 2020 · Жалоба Так исходники CS_initFLLSettle вроде как не секрет... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 71 20 мая, 2020 Опубликовано 20 мая, 2020 · Жалоба 9 minutes ago, Herz said: Да, похоже, я недооценил сложность процедуры смены частоты, хоть в документации так бодро заявлено: Придётся покопать глубже. Всё правильно заявлено, однако CS это не только DCO, который есть просто управляемый генератор, а ещё и FLL, который может этот генератор под любой другой более стабильный источник частоты (внутренний RC, кварц) подстраивать. То есть для DCO надо выставить диапазон через DCORSEL, а у FLL задать множители/делители. И он соответственно регистры MOD and DCO сам подстроит для совпадения с умноженной опорной частотой. А если поменять только рабочий диапазон DCORSEL, а FLL при этом по прежнему заставлять держать частоту 1МГц по умолчанию, то ничего хорошего не получится. можно FLL выключить и DCO руками покрутить, но его стабильность будет хуже чем у внутреннего 32кГц RC, частоту которого FLL по умолчанию и умножает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 29 мая, 2020 Опубликовано 29 мая, 2020 · Жалоба И снова странность, которой, вроде, никак быть не может. Работа eUSCI_B0 в режиме SPI, попытка обращения к SD-карточке. Частота DCO, опять же, по умолчанию. И выходит, что действительно ок. 1МГц. Сам SPI работает, как положено, SCLK порядка четверти мегагерца. Вот кусок кода, в котором специально выброшено всё лишнее. Карточки ещё нет, вход-выход соединены перемычкой. Порт Р3.0 будет использоваться как CS. Передаётся (и, соответственно, принимается) непрерывная последовательность из шести байт. //****************************************************************************** // Description: This program demonstrate USCI_B0 in SPI mode interfaced to a // SD-card. P1.0 indicate STE signal. // MCLK = SMCLK = DCO ~1MHz, BRCLK = SMCLK/4 = 264kHz // // // MSP430FR2355 // ----------------- // /|\| XIN|- // SD | | | // ------------- --|RST XOUT|- // | CS|<---|P3.0 | // | DATAOUT|--->|P1.3/UCB0SOMI | // | DATAIN |<---|P1.2/UCB0MOSI | // | I/O CLK|<---|P1.1/UCB0CLK | // | | | P1.0|--> LED/STE // // //****************************************************************************** #include <msp430.h> #define CS_HIGH P3OUT |= 0x01 #define CS_LOW P3OUT &= ~0x01 /** * main.c */ int main(void) { unsigned int data1, data2, i; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer // Disable the GPIO power-on default high-impedance mode // to activate previously configured port settings PM5CTL0 &= ~LOCKLPM5; // eUSCI_B0 Initializing UCB0CTL1 |= UCSWRST; // Enable SW reset P1DIR |= BIT0; // Set P1.0 to output direction P1SEL0 |= BIT0 + BIT1 + BIT2 + BIT3; // P1.0 - P1.3 USCI_B0 option select P3DIR |= BIT0; // P3.0 output direction (CS) UCB0CTLW0 |= UCMSB + UCMST + UCSYNC; // 8-bit SPI mstr, MSB 1st, sync UCB0CTLW0 |= UCMODE1 + UCSSEL1 + UCSTEM; // 4-pin mode, STE low, SMCLK UCB0BRW = 4; // division, clock eq. to BRCLK/4 UCB0STATW = 0; // clear errors UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation /* // initialize SD-card in SPI-mode and reset CS_HIGH; for (i=0; i<10; i++) // for more than 74 cycles { UCB0TXBUF = 0; // send clock pulses at CS high state while (!(UCB0IFG & UCTXIFG)); } */ // SD soft reset sequence CS_LOW; UCB0TXBUF = 0x40; while (!(UCB0IFG & UCTXIFG)); UCB0TXBUF = 0; while (!(UCB0IFG & UCTXIFG)); UCB0TXBUF = 0; while (!(UCB0IFG & UCTXIFG)); UCB0TXBUF = 0; while (!(UCB0IFG & UCTXIFG)); UCB0TXBUF = 0; while (!(UCB0IFG & UCTXIFG)); UCB0TXBUF = 0x95; while (!(UCB0IFG & UCRXIFG)); // USCI_B0 RX buffer ready? data2 = UCB0RXBUF; CS_HIGH; И всё бы хорошо, но почему-то уровень на CS возвращается в лог.1 только через 60 мсек! На картинке - красный луч. Зелёный - данные, синий - клок. Такое впечатление, что МК на это время просто засыпает... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 71 29 мая, 2020 Опубликовано 29 мая, 2020 · Жалоба вы используете 4 проводный режим SPI мастера, но при этом чипселект (причем другой, а не аппаратный к USCI привязанный) сами пытаетесь руками дергать. уберите UCMODE1. и у мастера вроде как два выхода должно быть клоки и mosi, а не один: P1DIR |= BIT0; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 29 мая, 2020 Опубликовано 29 мая, 2020 · Жалоба Да, я использую 4-проводный режим SPI, просто для проверки работы сигнала STE. На поведение порта Р3.0 это никак не сказывается, да и не должно. Ещё, несмотря на то, что только один пин порта 1 указан явно как выход ( P1DIR |= BIT0;), оба сигнала (MOSI и SCLK) формируются нормально, это не проблема. Я думаю, так и должно быть: когда мы определяем выводы порта, работающие с периферийным модулем eUSCI, уже неважно, как они настроены в смысле порта ввода-вывода - выходы или входы... То есть, странность именно в запаздывании реакции на команду P3OUT |= 0x01; что, как бы, никакого отношения к SPI не имеет. Как видно по осциллограмме, коммуникация давным-давно закончилась... Ума не приложу, что за задержка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 29 мая, 2020 Опубликовано 29 мая, 2020 · Жалоба Кстати, вот такой малоотличимый от вышеприведенного код выполняется вполне корректно: //****************************************************************************** #include <msp430.h> /** * main.c */ int main(void) { unsigned int data1, data2; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer // Disable the GPIO power-on default high-impedance mode // to activate previously configured port settings PM5CTL0 &= ~LOCKLPM5; // eUSCI_B0 Initializing UCB0CTL1 |= UCSWRST; // Enable SW reset P1DIR |= BIT0; // Set P1.0 to output direction P1SEL0 |= BIT0 + BIT1 + BIT2 + BIT3; // P1.0 - P1.3 USCI_B0 option select P3DIR |= BIT0; // P3.0 output direction (CS) UCB0CTLW0 |= UCMSB + UCMST + UCSYNC; // 8-bit SPI mstr, MSB 1st, sync UCB0CTLW0 |= UCMODE1 + UCSSEL1 + UCSTEM; // 4-pin mode, STE low, SMCLK UCB0BRW = 4; // division, clock eq. to BRCLK/4 UCB0STATW = 0; // clear errors UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation data1 = 0xAA; while(1) { P1OUT &= ~0x01; // P1.0 = 0 (LED off) P3OUT &= ~0x01; // Enable slave, /CS - low UCB0TXBUF = data1; // Write to transmitter to start SPI while (!(UCB0IFG & UCRXIFG)); // USCI_B0 RX buffer ready? data2 = UCB0RXBUF; // P3OUT |= 0x01; // Disable slave, /CS set if (data1 == data2) // Test for correct character RX'd P1OUT |= 0x01; // P1.0 = 1 (LED on) } return 0; } Здесь на осциллограмме ниже: синий и красный лучи, как и прежде, SCLK и P3.0 соответственно; зелёный - аппаратный STE. Как видно, использование аппаратного чипселекта выгоднее, можно сделать меньшими паузы между посылками. Что естественно. (У меня такой возможности нет, поскольку инициализация SD-карты предполагает подачу, как минимум, 74 периода SCLK при высоком уровне CS). Но ни о каких миллисекундах тут и речи нет... Длительность низкого уровня на P3.0 - 48 мкск. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
controller_m30 1 29 мая, 2020 Опубликовано 29 мая, 2020 · Жалоба Попробуйте такие варианты: 1. Перед записью байта 0х95 сделайте упреждающее чтение регистра UCBxRXBUF, чтобы очистить флаг UCRXIFG, который установлен прошлыми принятыми байтами. 2. Замените все команды while (!(UCB0IFG & UCTXIFG)); т.е. проверку опустошения буфера записи на проверку заполнения буфера чтения: while (!(UCB0IFG & UCRXIFG)); с обязательным считыванием регистра UCBxRXBUF для того, чтобы флаг UCRXIFG сбрасывался. Идея в том, что UCTXIFG=1 уже в начале передачи данных, а UCRXIFG=1 только в конце SPI-транзакции. Замена команд нужна для того, чтобы гарантированно привязаться к моменту завершения каждой SPI-транзакции. Может это на что-то повлияет. 3. Вставьте команды CS_LOW; CS_HIGH; между каждым передаваемым байтом, чтоб посмотреть на время реакции процессора при передаче всех предыдущих данных. Происходит ли задержка 60 мсек каждый раз, или только в конце пересылки группы байт? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 5 30 мая, 2020 Опубликовано 30 мая, 2020 · Жалоба Спасибо за советы. К сожалению, ничего из этого ситуацию не изменило и прояснить её не помогло. Замена проверки буфера передатчика на проверку буфера приёмника (конечно, со сбросом соответствующего флага) ни на что не повлияло. Чуть растянуло, разумеется, коммуникацию. Манипуляция сигналом CS в промежутках между пересылкой байтов тоже отрабатывается корректно, без жуткой задержки. Происходит она, как и прежде, только в конце. Тут, очевидно, что-то компилятор наоптимизировал. Сначала я обнаружил, что он переменные data1 и data2 вообще считал (когда ему было удобно) одной и той же ячейкой памяти, пока я не объявил их volatile. Ну, имел право, раз я данными не пользовался... И вот ещё один интересный момент. Если я заканчиваю транзакцию так, как показал выше, то есть: while (!(UCB0IFG & UCRXIFG)); // USCI_B0 RX buffer ready? data2 = UCB0RXBUF; CS_HIGH; то дикая задержка в 60 мс наличествует. Если же меняю местами чтение буфера с установкой CS в 1: while (!(UCB0IFG & UCRXIFG)); // USCI_B0 RX buffer ready? CS_HIGH; data2 = UCB0RXBUF; то она исчезает. После последнего импульса клока до поднятия ноги P3.0 проходит 10 мкс. Можно было бы предположить, что именно чтение буфера происходит, почему-то, так долго. Но если я вообще убираю чтение буфера: while (!(UCB0IFG & UCRXIFG)); CS_HIGH; // data2 = UCB0RXBUF; то задержка чудесным образом возвращается! Однако, дизассемблер ничего лишнего не указывает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться