Проблемы с передачей USART на PIC

Я пытаюсь отправить данные на SD-карту с PIC18f4580, но PIC не отправляет то, что должно быть.

связанные глобальные переменные:

unsigned char TXBuffer[128]; //tx buffer
unsigned char TXCurrentPos = 0x00; //tracks the next byte to be sent
unsigned char TXEndPos = 0x00; //tracks where new data should be put into the array

Я добавляю данные в буфер, используя следующую функцию:

void addToBuffer(char data){

    TXBuffer[TXEndPos] = data;
    TXEndPos++;
}

И помещаем данные из TXBuffer в TXREG со следующим прерыванием:

else if (PIR1bits.TXIF == 1){

    if((TXEndPos - TXCurrentPos) > 0){         // if there is data in the buffer
        TXREG = TXBuffer[TXCurrentPos];           // send next byte
        TXCurrentPos++;               // update to the new position
    }

Используя осциллограф, я вижу, что PIC отправляет 0x98, независимо от того, что я помещаю в буфер. На самом деле я никогда не помещал 0x98 в буфер.

Однако, если я заменю

TXREG = TXBuffer[TXCurrentPos];

с

TXREG = 0x55;

или

TXREG = TXCurrentPos;

тогда я получаю ожидаемые результаты, то есть PIC будет повторно отправлять 0x55 или считать от 0 соответственно.

Так почему же у PIC возникают проблемы с отправкой данных из массива, а в остальное время все нормально? Я подчеркну, что передача обрабатывается в прерывании, потому что я чувствую, что это корень моей проблемы.

РЕДАКТИРОВАТЬ: Это циклический буфер в том смысле, что TXEndPos и ​​TXCurrentPos возвращаются к 0, когда они достигают 127. Я также отключаю прерывание передачи, когда TXEndPos - TXCurrentPos == 0, и снова включаю его при добавлении данных в буфер. Действительно, мой код работает полностью так, как ожидалось, в том смысле, что если я добавлю 13 символов в TXBuffer в main, мой PIC передаст 13 символов, а затем остановится. Проблема в том, что они всегда одного и того же (неправильного) символа — 0x98.

EDIT2: более полные функции здесь: http://pastebin.com/MyYz1Qzq

EDIT3: изменив наш скрипт компоновщика и соответствующим образом используя прагмы, мы можем получить некоторые из наших данных в наш буфер. Мы статически разместили переменные, связанные с буфером, в тот же банк памяти, и это, безусловно, помогло, но не все наши данные попадают в наш буфер. Самое странное, что при многократном запуске программы в буфере появляются разные данные, хотя все данные, которые должны быть помещены в буфер, определены в нашем коде. Кроме того, мы получаем совершенно разные результаты, когда pic автоматически запускается после его программирования, когда мы отключаем питание и перезапускаем питание с все еще подключенным pickit3, и когда мы сбрасываем питание с отключенным pickit3. Кроме того, моделирование в MPLAB приводит к идеальному заполнению буфера, однако при фактическом запуске кода на PIC и просмотре его памяти это не так.

Наш код на 5:38 22.09.10 здесь .

Наш измененный файл компоновщика находится здесь .

Какой компилятор вы используете. Это похоже на c18, с которым я работаю, дайте мне знать, и я могу просто скомпилировать это для PIC и протестировать его самостоятельно.
@Kortuk: я использую MPLAB c18 Lite. Если вы хотите попробовать, это здесь: pastebin.com/ZYcZG0eW .
Джон, моей следующей заметкой, когда я ее загрузил, было использование volatile. Если вы используете что-то, что будет изменяться как внутри прерываний, так и снаружи, пометьте это как volatile. Однако это не должно быть проблемой, поскольку c18 lite не оптимизирует, а без оптимизатора volatile ничего не значит.
Это будет позже на неделе, прежде чем я окажусь в лаборатории со свободным временем. У моих студентов есть работа в четверг, я постараюсь загрузить ее к тому времени, это может быть на следующей неделе.
Мы изменили все переменные, измененные или прочитанные внутри прерываний, на volatile, но это ничего не изменило, как ожидалось. Если мы решим нашу проблему раньше, я отпишусь здесь, чтобы сообщить вам. Я могу в конечном итоге переписать большую часть кода, чтобы посмотреть, поможет ли это. Сейчас главное — это просто инициализация, за которой следует тестовый код, прямо сейчас просто добавление некоторых данных в массив, а затем включение прерывания TX. Спасибо, что заглянули!
volatile не влияет на вас. Вы не используете оптимизатор. Вы смотрели на ответ от Питера Гибсона?

Ответы (5)

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

TXREG = TXBuffer[TXEndPos];           // send next byte

должно быть

TXREG = TXBuffer[TXCurrentPos];           // send next byte

Важно копировать/вставлять код напрямую (использование pastebin — это здорово!), потому что вы фактически исправили это самостоятельно в вопросе, из-за чего людям трудно обнаружить проблему :)

Возможно, это было бы легче заметить самостоятельно, если бы вы инициализировали буфер известным значением при запуске (например, 0x5A).

Вы также упомянули, что в какой-то момент вы сбросили переменные TxCurrentPos& TxEndPosдо нуля, но я не вижу этого в вашем коде. Лучше всего делать это всякий раз, когда вы увеличиваете эти значения. Например

TxCurrentPos++;
TxCurrentPos %= TX_BUFFER_SIZE;

В сторону: мне нравится, что вы удалили избыточную переменную TxBufferSize в вопросе - это следует принципу DRY и устраняет источник ошибки. Дублирование данных в двух местах вызывает проблемы.

Я собирался инициализировать код, а затем запустить его, чтобы увидеть, есть ли изменения, и если да, то какой тип ошибки я собирался искать. Хороший улов
Эта ошибка была результатом того, что я изменил эту строку для отладки и попытался изменить ее обратно из памяти. С тех пор это было исправлено, и проблема сохраняется. Однако это завело нас в тупик, потому что мы получали результаты, но мы поняли это вскоре после того, как я разместил код здесь.

Несколько вещей, которые можно попробовать:
1) Убедитесь, что ваш буфер инициализирован, это скажет вам, исходит ли 0x98 из буфера или откуда-то еще.
2) Отключить прерывания при добавлении элементов в буфер

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

Я не вижу ничего, что делало бы ваш буфер круглым. Я думаю, что вы полагаетесь на переполнение, чтобы получить от 127 до 0... но беззнаковый символ может представлять значения от 0 до 255. Таким образом, ваш TXCurrentPos будет идти прямо с конца вашего массива.

Я также видел, как компиляторы PIC C делали некоторые странные вещи без уважительной причины. Большинство компиляторов также могут выводить собранную версию программы; возможно, стоит некоторое время просмотреть листинг ассемблера и посмотреть, как компилируется C. В зависимости от типа данных, объявленного как TXREG, компилятор может попытаться выполнить приведение типов.

Кроме того, в вашем коде приема в прерывании вы ДОЛЖНЫ проверить приемник на наличие состояния переполнения и очистить его. Каждый. Одинокий. Время. Приемник RS232 отказывается принимать дополнительные данные, пока установлен бит ошибки переполнения.

void ClearRXOverRun()
{
    // If there's a frame overrun, RS232 will refuse to receive
    if (OERR == 1)
    {
        // Clear overrun condition by turning RX off and back on
        CREN = 0;
        CREN = 1;   
    }   
}   
Код pastebin, в котором все это есть, обнуляет счетчик.
Оно делает? Где?
Он инициализирован 0 вверху, но я нажал ctrl-f для TXCurrentPos и ​​нашел только инициализатор и инкрементатор.
Я думал, что видел это, у меня нет времени смотреть сейчас. Извините, если я ошибаюсь.
Нажмите изменить свой ответ ajs410. Просто поменяй что-нибудь очень незначительное для меня.
Первоначально мы собирались иметь буфер размером 256 байт, что означало, что мы могли рассчитывать на переполнение для обнуления указателей, но мы столкнулись с ошибками компиляции, поскольку размер банков данных составляет 256 байт. Я уменьшил размер буфера до 128, но забыл изменить код, чтобы обнулить указатели после 128 байт. В любом случае, мы пытались поместить в буфер около 40 байт и все еще сталкивались с этой проблемой. Последняя версия кода правильно обнуляет указатели, и я скоро опубликую этот код.

Мне жаль, что это может показаться очень простым, но пробовали ли вы записывать свои данные в EEPROM, а затем читать их позже, чтобы убедиться, что вы действительно назначаете правильные данные массиву? Если данные, которые назначаются буферу, не являются допустимыми данными, то это может быть вашей проблемой?

Для этого типа проблемы я делю проблему еще дальше, чем обычно смотрю на сборку. Также я видел проблемы, когда RX мог повредить или переполнить буфер, поэтому я отключил RX, пока у вас не заработает TX.

Первое, что я бы сделал, это двигаться

if(waitingForACK == 0){
    PIE1bits.TXIE = 1; //Enable the TX interrupt
} 

из addToBuffer в собственную функцию. Затем вызывайте его, когда буфер заполнен, а не по ходу дела. Это может быть какая-то проблема с синхронизацией, когда вы не можете добавить, пока прерывание отправляет данные. Когда я передаю пакет, я обычно отключаю прерывание TX, заполняю буфер TX, а затем включаю прерывание TX.

Затем проверьте кольцевой буфер вне прерывания. В вашей основной функции заполните буфер, а затем прочитайте данные.

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

volatile unsigned char temp;
if((TXEndPos - TXCurrentPos) > 0)            // if there is data in the buffer
{                                              
    temp  = TXBuffer[TXCurrentPos]; 
    Nop();                                   // for adding breakpoints
    Nop();
    Nop();
    // add error checking to make sure TXREG is empty.
    TXREG = temp;                            // send next byte
    TXCurrentPos = TXCurrentPos + 0x01;      // update to the new position

Еще одна маленькая вещь заключается в том, что я бы также рассмотрел возможность изменения

else if (PIR1bits.TXIF == 1){

к

if (PIR1bits.TXIF == 1){

чтобы убедиться, что другие прерывания не истощают прерывание TX.

Затем, если у вас все еще есть проблема, посмотрите на код сборки, я видел, где компилятор делает что-то странное, и это обычно очевидно, если вы посмотрите на сборку.