Я пытаюсь отправить данные на 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 здесь .
Наш измененный файл компоновщика находится здесь .
Немного сбивает с толку то, что код в вопросе отличается от кода в 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;
}
}
Мне жаль, что это может показаться очень простым, но пробовали ли вы записывать свои данные в 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.
Затем, если у вас все еще есть проблема, посмотрите на код сборки, я видел, где компилятор делает что-то странное, и это обычно очевидно, если вы посмотрите на сборку.
Кортук
Джон Моффит
Кортук
Кортук
Джон Моффит
Кортук