Я программирую связь SPI с внешним чипом RF. Микроконтроллер - модель PIC24FJ64GA102 от Microchip.
Я хочу использовать расширенный буферный режим SPI.
Проблема: получить полученные байты из приемного буфера.
Используемая функция SPI:
void SPI1_get(uint8_t* data, uint16_t length) {
uint16_t i = 0, l = length;
uint8_t dummy;
while (length > 0) {
while (SPI1STATbits.SPITBF || SPI1STATbits.SPIRBF) {
dummy = SPI1STAT;
}
do {
SPI1BUF = 0xff;
} while (SPI1STATbits.SPIRBF == 0 && --length > 0);
do {
while (SPI1STATbits.SRMPT == 0) {
}
data[i] = SPI1BUF;
++i;
} while (i < l && SPI1STATbits.SRXMPT != 1);
}
}
Здесь звонки:
uint8_t cmd[2]; cmd[0] = length; cmd[1] = address;
SPI1_put(cmd,2); // e.g: 0x02, 0x01
SPI1_get(buf,2); // e.g: 0x05, 0x01 (received data)
Связь в порядке, проверено осциллографом и модулем декодирования SPI. Данные на шине SPI аналогичны приведенному выше комментарию: отправлено 0x02 0x01 0xff 0xff
, получено 0x00 0x00 0x05 0x01
, но функция выше неправильно извлекает данные из буфера приема. Я уже протестировал множество комбинаций проверки флагов и прерываний, но в итоге лучший результат, который я могу получить, это: 0x00 0x01
(правильный только последний байт).
Также уже проверил список ошибок, где упоминаются две проблемы SPI, которые не (не должны) влиять на мой код.
Что, черт возьми, я делаю не так ?!
В соответствии с просьбой здесь функция SPI1_put ():
void SPI1_put(uint8_t* data, uint16_t length) {
uint16_t i = 0;
uint8_t dummy;
for (; i < length; ++i) {
while (SPI1STATbits.SPITBF)
; // maybe change to (_SPI1BEC == 7) ?
SPI1BUF = data[i];
dummy = SPI1BUF; //dummy read
}
}
[последнее изменение: 05.02.2015]
Итак, сегодня я смог уделить больше времени этой конкретной проблеме и придумал порт предложения ElderBug, а также позаботился об ошибках, упомянутых в списке исправлений:
uint8_t out_buf[128];
uint8_t in_buf[128];
void SPI1_com(uint8_t* out, uint8_t* in, uint16_t out_len, uint16_t in_len) {
uint16_t len = out_len + in_len;
uint16_t sent = 0, recv = 0, i = 0;
// while (!SPI1STATbits.SRXMPT)
sent = SPI1BUF; // empty buffer
sent = SPI1BUF; // empty buffer
sent = 0;
if (out != out_buf && out != 0)
memcpy(out_buf, out, out_len);
while (sent < len && recv < len) {
if (SPI1STATbits.SPIBEC != 7 && sent < len) {
SPI1BUF = out_buf[sent++];
}
if (!SPI1STATbits.SRXMPT && recv < len) {
in_buf[recv] = SPI1BUF, recv++;
}
}
if (in != 0) {
for (i = 0; i < in_len; ++i) {
in[i] = in_buf[out_len + i];
}
// memcpy(in, in_buf + out_len, in_len);
}
for (i = 0; i < len; ++i) {
out_buf[i] = 0xff;
in_buf[i] = 0xff;
}
}
Этот код в основном работает. За исключением, с которым мне не удалось обойтись:
Связь работает следующим образом:
- 1 байт: r / w-бит + длина
- 1 байт: адрес
- 1–127 байт: данные
Итак, когда я читаю 1 байт из ведомого чипа, то есть отправляю 3 байта (rw + len, адрес, фиктивный байт), данные, которые у меня есть в моем in_buf
буфере, равны 0xFF. А теперь странная вещь: когда я просто прочитал еще один байт, ничего не меняя (еще один фиктивный байт на шине), первый байт моего in_buf
получил правильные данные. Но, похоже, это работает не всегда, потому что моя программа все еще застревает в некоторых моментах.
Я остался сидеть здесь с множеством вопросительных знаков.
Странная вещь 2-я: чтение 8 байтов, данные в моем буфере верны до последнего байта, последний байт равен 0xFF, должен быть 0x00. Wtf?
PS: Уже подал заявку в Microchip на поддержку по этому вопросу.
SPI1_put
? Проблема также может исходить оттуда. - person ElderBug   schedule 22.01.2015SPI1_put
функции не должно ли в разделе шагов циклаfor
бытьi++
вместо++i
? Потому что теперь вы никогда не обрабатываете 0-й байт буфера. - person Eimantas   schedule 22.01.2015c++
или++c
. И как я уже писал в своем вопросе, данные на самой шине (измеренные с помощью прицела) полностью верны. Проблема здесь в том, чтобы получить полученные данные из расширенного буфера SPI, а не из самого обмена. - person qwc   schedule 22.01.2015