Линия выбора главного чипа DSPIC33 SPI не работает

Я очень старался заставить шину SPI работать на DSPIC33EP128GM604. Я настроил SPI3 как стандартный 8-битный мастер-модуль и назначил контакт выбора микросхемы, чтобы я мог переключать ведомые устройства.

Я не могу заставить линию выбора микросхемы работать должным образом, кажется, что DSPIC не ожидает завершения передачи, прежде чем переключать линию выбора микросхемы с LOW на HIGH. Я проверил опечатки, и ничего не имеет отношения к этой проблеме. Кроме того, я попытался переключить линию CS на другой контакт. Я также пробовал модуль SPI 1, но проблема не устранена.

Вот мой код:

Конфигурация SPI 3:

void Init_SPI3 ( void )
{
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 0; // Disable the interrupt
// SPI1CON1 Register Settings
SPI3CON1bits.DISSCK = 0; // Internal serial clock is enabled
SPI3CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
SPI3CON1bits.MODE16 = 0; // Communication is word-wide (16 bits)
SPI3CON1bits.SSEN = 0; //No CS
SPI3CON1bits.MSTEN = 1; // Master mode disabled
SPI3CON1bits.PPRE = 2; //Pre-scaler
SPI3CON1bits.SPRE = 8;//Pre-scaler 2
SPI3CON1bits.SMP =1; // Input data is sampled at the middle of data output time
SPI3CON1bits.CKE =0; // Serial output data changes on transition from
SPI3CON1bits.CKP = 0; // Idle state for clock is a low level;
SPI3STATbits.SPIEN = 1; // Enable SPI module
// Interrupt Controller Settings
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 1; // Enable the interrupt
}

Конфигурация 3-контактного SPI:

TRISBbits.TRISB10 = 0; //Set SPI3CLK as output
TRISBbits.TRISB11 = 0; //Set SPI3DATAOUT as output

RPOR4bits.RP42R=32;  //SPI3_CLK out
RPOR4bits.RP43R=31;  //SPI3_DATA out

Конфигурация выводов линии выбора чипа:

TRISBbits.TRISB4 = 0; //SPI3 CS is on Pin B4, set it to Output

Простая основная процедура:

    while(1==1){

    PORTBbits.RB4 = 0;//Set CS line to low  
   WriteSPI3(0xaa); //This is from the peripheral library to be safe....
  PORTBbits.RB4 = 1; //Set CS line to high
                    }

Но вот вывод:

введите описание изображения здесь

В частности, в чем проблема, которую я должен видеть на картинке прицела?
Где вы устанавливаете режим SPI с CPOL и CPHA
биты .CKE и .CKP?
Извините - прошло много времени с тех пор, как я использовал dsPIC, и я привык к вызовам STM32F CMSIS. Вы уверены, что эти значения подходят для устройства, с которым вы пытаетесь поговорить?
Я даже не пробовал это еще. Проблема в том, что линия CS не переключается правильно. Если вы посмотрите на фиолетовую кривую (CS), она преждевременно изменит свое состояние. Я очень устал от DSPIC, так что я даю ему еще один день, прежде чем переключиться на STM32....
Почему вы не можете оставить бит CS низким и переключить его на другую сторону непосредственно перед тем, как установить его на высокий уровень? Это мешает чему-то? Установите соответствующий CS непосредственно перед выполнением связи и оставьте его там до следующего прохода.
afaik это часть с расширенным режимом. Значение флагов меняется в расширенном режиме. Убедитесь, что вы отключили расширенный режим (см. бит spi<x>con2.SPIBEN)

Ответы (2)

Судя по техническому описанию и примерным кодам, флага приемного буфера достаточно, чтобы сообщить нам, когда событие TX завершено, и, таким образом, CS может переключиться. Немного странно, почему для этого чипа нет флага, сообщающего нам, когда регистр сдвига SPI передал все свои данные. Весь код примера проверяет только флаг буфера приема.

После долгих размышлений, проб и ошибок и, наконец, форумов по микрочипам я могу подтвердить, что этот код работает :

   uint8_t Write_SPI1(uint8_t command) { //Does work    
    SPI1BUF = command; // send data over SPI
    while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high  
    return SPI1BUF; //KEY STATEMENT THAT MADE A DIFFERENCE, Return the actual data received
    }

Наряду с этим кодом, если ваше периферийное устройство зависит от выбора периферийного контакта (SPI2, SPI3 и т. д.), важно определить не только SPI Clock Out, но и SPI Clock In, даже если вы находитесь в ведущем режиме .

Однако меня сбивает с толку то, что этот код (который, я думаю, должен делать то же самое) не работает:

  void Write_SPI1(uint8_t command) { //Does not work, premature toggle of CS, tried this code initially....
    uint8_t garbage;
    SPI1BUF = command; // send data over SPI
    while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high 
    garbage = SPI1BUF; // read dummy data, does not seem to clear the flag as expected
    }
Странный. Просто мысль - вы пытались отключить оптимизацию перед компиляцией ?? Похоже, ваш компилятор использует ярлыки, которые вам не нужны, и отключение оптимизации может улучшить ситуацию.
На самом деле компилятор может увидеть «мусор» как никогда не используемый и оптимизировать всю строку. Он не может оптимизировать возвращаемое значение.
... или попробуйте добавить volatile в объявление мусора.
добавление volatile не работает. Но возврат мусора вместо SPI1BUF тоже работает. Хммм, звучит как перк компилятора.

Подождите, пока передача SPI не будет завершена, прежде чем отменить выбор чипа с помощью чего-то вроде

 while(SPI3_Tx_Buf_Full);  //wait till completion of transmission

См. пример использования SPI1 по адресу http://pat.cybersites.ca/docs/PIC24F/SPI_Example1.html .

Я предполагал, что периферийная библиотека позаботится об этом. Тем не менее, я нашел эквивалентный флаг для своего чипа: while(SPI3STATbits.SPITBF){};не имеет значения, модуль каким-то образом неправильно устанавливает флаг?
SPITBFуказывает только на то, есть ли биты в буфере, а не на то, идет ли передача. После того, как whileвы добавили оператор, попробуйте while(!SPI3STATbits.SPIRBF)удерживать, пока передача не будет завершена и что-то не будет помещено в буфер приема (даже если вы ничего с этим не делаете).
SPI3_Tx_Buf_Fullдолжен быть макрос, проверяющий правильный бит. Вы сами утверждаете CS с помощью PORTBbits.RB4 = 0, поэтому вы также должны сами его отменить. Вам просто нужно дождаться, пока периферийное устройство закончит смещение битов. Если бы библиотека делала это сама ПОСЛЕ запуска передачи, это просто тратило бы впустую циклы ЦП, которые вы, возможно, захотите использовать каким-то другим способом. Может быть встроенная проверка перед записью следующего значения внутрь WriteSPI3. Но это до запуска периферии, а не после
Я попытался добавить: while(!SPI3STATbits.SPIRBF): Никаких изменений, за исключением того факта, что CS поддерживается немного дольше, и я получаю только одну передачу, после которой Pic ничего не делает, поэтому он явно зацикливается на этом операторе while.
@AdilMalik, вы путаете буфер TX со сдвиговым регистром TX. Сдвиговый регистр — это то место, откуда фактически отправляются биты, а буфер — это то место, откуда ваш код загружает их. Модуль внутренне передает ваш байт данных из буфера в регистр сдвига, поскольку он готовится к его отправке (предоставляя вам индикацию флага SPITBF), но в этот момент биты все еще находятся в регистре сдвига и не были отправлены. еще. если вы используете SPIRBF в качестве флага, чтобы сообщить вам, когда транзакция завершена, вам нужно убедиться, что вы сначала очистили буфер RX, чтобы флаг SPIRBF начал очищаться.
Возможно, SPIxSTAT.SPIBUSY может работать, если SPITBE этого не делает.
Или установите SPIxSTAT.SISEL в режим 5 (0b101) и используйте прерывание SPI в качестве флага, указывающего, когда был отправлен последний бит.
Перепробовал все предложения, похоже, ничего не работает: 1) SPIxSTAT.SPIBUSY не является допустимым битом для моего устройства 2) Создал функцию прерывания: void __attribute__((interrupt,auto_psv)) _SPI3Interrupt(void) { PORTBbits.RB4 = 1; }и установил .SISEL на 5. Все еще никаких изменений. Я начинаю думать, что это возможная ошибка?
Я предполагаю, что вы не забыли закомментировать RB4=1 в своем основном цикле...? Хотя на самом деле я бы не стал использовать функцию прерывания - просто подождите в вашем основном цикле, пока флаг прерывания не будет установлен с помощью while (!whatever_the_irq_flag_bit_is);
А если вы пытаетесь использовать метод SPIxRBF, перед началом передачи убедитесь, что флаг RBF снят.
@AdilMalik - «это возможная ошибка?» Предполагая, что ваш сигнал -CS представляет собой фиолетовую линию на вашей фотографии с прицелом, тогда нет , я бы не стал искать ошибку DSPIC33. Это потому, что сигнал -CS, такой как эта фиолетовая линия, никогда не будет работать для обычного ведомого SPI, а такая серьезная ошибка будет хорошо известна. Я не использую этот MCU, но если бы я был на вашем месте, в дополнение к полезным советам, которые вы получаете, я бы начал с поиска рабочего образца кода SPI. Вот поток EE.SE, который содержит заявленный как работающий пример SPI Master .
Я просмотрел множество примеров SPI, предоставленных Microchip. Начнем с того, что код, который они предоставляют, имеет конфликтующие значения, когда флаг находится в состоянии TX и т. Д. Однако основной метод такой же, как и многие люди, приведенные выше. Вот один из раздела «Пример кода» DSPIC.
void Write_SPI1 ( int16_t command ) { int16_t temp; PORTBbits.RB7 = 0; // lower the slave select line temp = SPI1BUF; // dummy read of the SPI1BUF register to clear the SPIRBF flag SPI1BUF = command; // write the data out to the SPI peripheral while( !SPI1STATbits.SPITBF ) // wait for the data to be sent out ; PORTBbits.RB7 = 1; // raise the slave select line }
void Write_SPI2 ( int16_t command ) { int16_t temp; PORTBbits.RB6 = 0; // lower the slave select line temp = SPI1BUF; // dummy read of the SPI1BUF register to clear the SPIRBF flag SPI1BUF = command; // write the data out to the SPI peripheral while( !SPI1STATbits.SPIRBF ) // wait for the data to be sent out ; PORTBbits.RB6 = 1; // raise the slave select line }
Таким образом, для функционально одной и той же процедуры они проверяют 2 флага difernet, тем не менее, идея та же. В обоих случаях не работает. Но если я потрачу несколько циклов на цикл for, вывод CS будет правильно переключаться, как и ожидалось.