|
ARM 7 (at91sam7x) Драйвер для UART |
|
|
|
Oct 9 2012, 12:16
|
Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418

|
Приветствую, Благородные Доны и Донны. Занимаюсь программированием микроконтроллеров недавно. Написал драйвер для UART и надеюсь услышать критику и предложения. Может быть пригодится кому... Просто, кроме страшного атмеловского примера и нескольких весьма специфичных реализаций, внятного примера работы с Uart я не нашел... Не ругайте за отсутствие комментариев... Старался писать код максимально понятно... usart_ex.h CODE #ifndef USART_EX_H #define USART_EX_H //----------------------------------------------------------------------------- #include <board.h> //----------------------------------------------------------------------------- namespace usart { typedef unsigned int handle_type; typedef unsigned int id_type; typedef unsigned int mode_type; typedef unsigned int size_type; typedef unsigned int baudrate_type; typedef unsigned char error_type; typedef unsigned int sync_frequency_type; //--------------------------------------------------------------------------- enum { TX_BUFFER_SIZE = 128, RX_BUFFER_SIZE = 128 }; // доступные интерфейсы usart enum EUsartId { id0 = 0, id1 = 1, idCount, idInvalid = 0xFF }; // ошибки usart enum EUsartError { eOk = 0, eTxBufferOverflow = 1, eRxBufferOverflow = 2, eFrameError = AT91C_US_FRAME, eReceiveOverrun = AT91C_US_OVRE, eParityError = AT91C_US_PARE, eHardwareError = eFrameError | eReceiveOverrun | eParityError }; //--------------------------------------------------------------------------- void Init(void); handle_type Open(const id_type usartId, const mode_type mode, const baudrate_type baudRate, const sync_frequency_type masterClockFrequency = BOARD_MCK); bool IsError(const handle_type handle); error_type Error(const handle_type handle); bool IsInvalidHandle(const handle_type handle); bool IsDataAvailableForReading(const handle_type handle); void WaitForData(const handle_type handle); size_type Read(const handle_type handle, unsigned char* const data); size_type ReadBuffer(const handle_type handle, unsigned char* const buffer, const size_type bufferSize); void Write(const handle_type handle, const unsigned char data); void WriteBuffer(const handle_type handle, const unsigned char* const buffer, const size_type bufferSize); void Flush(const handle_type handle); void RFlush(const handle_type handle); void WFlush(const handle_type handle); void Close(handle_type* const handle); //--------------------------------------------------------------------------- } #endif
usart_ex.cpp CODE #include "usart_ex.h" #include "..\kernel\ring_buffer.h" #include <board.h> #include <pio/pio.h> #include <irq/irq.h> #include <pmc/pmc.h> #include <utility/assert.h> #include <utility/math.h> //-----------------------------------------------------------------------------
namespace usart { namespace tools { typedef void (*FIrqHandlerCPtr)(void);
struct CUsartInfo { unsigned int id_; AT91S_USART* usart_; FIrqHandlerCPtr irqHandler_; unsigned char txBuffer_[TX_BUFFER_SIZE]; unsigned char rxBuffer_[RX_BUFFER_SIZE]; struct kernel::ringb::CRingBuffer txRingBuffer_; struct kernel::ringb::CRingBuffer rxRingBuffer_; }; //--------------------------------------------------------------------------- static struct CUsartInfo usarts_[idCount]; static error_type usartErrors_[idCount]; static const Pin usartPins_[] = { BOARD_PIN_USART_RXD, BOARD_PIN_USART_TXD, BOARD_PIN_USART_CTS, BOARD_PIN_USART_RTS }; //---------------------------------------------------------------------------
inline void doIrqHandler(handle_type handle) { tools::CUsartInfo* const info = &tools::usarts_[handle]; unsigned int status = info->usart_->US_CSR; status &= info->usart_->US_IMR; if ((status & eHardwareError)) { usartErrors_[id0] |= (status & eHardwareError); info->usart_->US_IDR = AT91C_US_TXRDY | AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; } if ((status & AT91C_US_TXRDY) == AT91C_US_TXRDY) { if (kernel::ringb::IsEmpty(&info->txRingBuffer_)) { info->usart_->US_IDR = AT91C_US_TXRDY; } else { unsigned char writedToken(0); kernel::ringb::Read(&info->txRingBuffer_, writedToken); info->usart_->US_THR = writedToken; } } if ((status & AT91C_US_RXRDY) == AT91C_US_RXRDY) { if (kernel::ringb::IsFull(&info->rxRingBuffer_)) { volatile const unsigned int rhr = info->usart_->US_RHR; usartErrors_[id0] |= eRxBufferOverflow; return; } kernel::ringb::Write(&info->rxRingBuffer_, info->usart_->US_RHR); } }
void IrqHandler0(void) { doIrqHandler(id0); } void IrqHandler1(void) { doIrqHandler(id1); } } //---------------------------------------------------------------------------
void Init(void) { PIO_Configure(tools::usartPins_, PIO_LISTSIZE(tools::usartPins_));
tools::usarts_[id0].usart_ = AT91C_BASE_US0; tools::usarts_[id0].id_ = AT91C_ID_US0; tools::usarts_[id0].irqHandler_ = tools::IrqHandler0;
tools::usarts_[id1].usart_ = AT91C_BASE_US1; tools::usarts_[id1].id_ = AT91C_ID_US1; tools::usarts_[id1].irqHandler_ = tools::IrqHandler1; for (unsigned char i(0); i < idCount; ++i) { kernel::ringb::Init(&tools::usarts_[i].txRingBuffer_, tools::usarts_[i].txBuffer_, TX_BUFFER_SIZE); kernel::ringb::Init(&tools::usarts_[i].rxRingBuffer_, tools::usarts_[i].rxBuffer_, RX_BUFFER_SIZE); tools::usartErrors_[i] = eOk; } } //--------------------------------------------------------------------------- handle_type Open(const id_type usartId, const mode_type mode, const baudrate_type baudRate, const sync_frequency_type masterClockFrequency) { SANITY_CHECK(usartId < idCount && baudRate && ((mode & AT91C_US_USMODE_ISO7816_0) != AT91C_US_USMODE_ISO7816_0) && ((mode & AT91C_US_USMODE_ISO7816_1) != AT91C_US_USMODE_ISO7816_1) && ((mode & AT91C_US_USMODE_IRDA) != AT91C_US_USMODE_IRDA)); tools::CUsartInfo* const info = &tools::usarts_[usartId];
kernel::ringb::Clear(&info->txRingBuffer_); kernel::ringb::Clear(&info->rxRingBuffer_); tools::usartErrors_[usartId] = eOk; PMC_EnablePeripheral(info->id_);
info->usart_->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA; info->usart_->US_MR = mode; if ((info->usart_->US_MR & AT91C_US_SYNC)) { info->usart_->US_BRGR = masterClockFrequency / baudRate; } else { const unsigned char freqSemplingMode = (info->usart_->US_MR & AT91C_US_OVER) ? 1 : 2; info->usart_->US_BRGR = masterClockFrequency / (8 * freqSemplingMode * baudRate); }
info->usart_->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; info->usart_->US_CR = AT91C_US_RXEN | AT91C_US_TXEN ;
IRQ_ConfigureIT(info->id_, 0, info->irqHandler_); IRQ_EnableIT(info->id_); return usartId; } //--------------------------------------------------------------------------- bool IsError(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return tools::usartErrors_[handle] != eOk; } //--------------------------------------------------------------------------- error_type Error(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return tools::usartErrors_[handle]; } //--------------------------------------------------------------------------- bool IsInvalidHandle(const handle_type handle) { return handle >= idCount; } //--------------------------------------------------------------------------- bool IsDataAvailableForReading(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return !kernel::ringb::IsEmpty(&tools::usarts_[handle].rxRingBuffer_); } //--------------------------------------------------------------------------- void WaitForData(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle));
while (!IsDataAvailableForReading(handle)) { continue; } } //--------------------------------------------------------------------------- size_type Read(const handle_type handle, unsigned char* const data) { SANITY_CHECK(!IsInvalidHandle(handle) && data); tools::CUsartInfo* const info = &tools::usarts_[handle]; if (!kernel::ringb::IsEmpty(&info->rxRingBuffer_)) { return kernel::ringb::Read(&info->rxRingBuffer_, *data); } return 0; } //--------------------------------------------------------------------------- size_type ReadBuffer(const handle_type handle, unsigned char* const buffer, const size_type bufferSize) { SANITY_CHECK(!IsInvalidHandle(handle) && buffer && bufferSize > 0);
tools::CUsartInfo* const info = &tools::usarts_[handle]; if (!kernel::ringb::IsEmpty(&info->rxRingBuffer_)) { return kernel::ringb::ReadBuffer(&info->rxRingBuffer_, buffer, min(bufferSize, kernel::ringb::Size(&info->rxRingBuffer_))); } return 0; } //--------------------------------------------------------------------------- void Write(const handle_type handle, const unsigned char data) { SANITY_CHECK(!IsInvalidHandle(handle));
tools::CUsartInfo* const info = &tools::usarts_[handle];
if (kernel::ringb::IsFull(&info->txRingBuffer_)) { tools::usartErrors_[handle] |= eTxBufferOverflow; return; } const bool isEnableInterrupt = kernel::ringb::IsEmpty(&info->txRingBuffer_); kernel::ringb::Write(&info->txRingBuffer_, data); if (isEnableInterrupt) { info->usart_->US_IER = AT91C_US_TXRDY; } } //--------------------------------------------------------------------------- void WriteBuffer(const handle_type handle, const unsigned char* const buffer, const size_type bufferSize) { SANITY_CHECK(!IsInvalidHandle(handle));
if (!bufferSize) { return; } tools::CUsartInfo* const info = &tools::usarts_[handle];
if (kernel::ringb::IsFull(&info->txRingBuffer_) || bufferSize > kernel::ringb::Capacity(&info->txRingBuffer_) - kernel::ringb::Size(&info->txRingBuffer_)) { tools::usartErrors_[handle] |= eTxBufferOverflow; return; } const bool isEnableInterrupt = kernel::ringb::IsEmpty(&info->txRingBuffer_); kernel::ringb::WriteBuffer(&info->txRingBuffer_, buffer, bufferSize); if (isEnableInterrupt) { info->usart_->US_IER = AT91C_US_TXRDY; }
} //--------------------------------------------------------------------------- void Flush(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); tools::CUsartInfo* const info = &tools::usarts_[handle]; info->usart_->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; info->usart_->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA; } //--------------------------------------------------------------------------- void RFlush(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); tools::CUsartInfo* const info = &tools::usarts_[handle]; info->usart_->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; info->usart_->US_CR = AT91C_US_RSTTX | AT91C_US_RSTSTA; } //--------------------------------------------------------------------------- void WFlush(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); tools::CUsartInfo* const info = &tools::usarts_[handle]; info->usart_->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; info->usart_->US_CR = AT91C_US_RSTTX | AT91C_US_RSTSTA; } //--------------------------------------------------------------------------- void Close(handle_type* const handle) { SANITY_CHECK(!IsInvalidHandle(*handle)); tools::CUsartInfo* const info = &tools::usarts_[*handle]; info->usart_->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS; IRQ_DisableIT(info->id_); PMC_DisablePeripheral(info->id_); *handle = idInvalid; } //--------------------------------------------------------------------------- }
ring_buffer.h CODE #ifndef RING_BUFFER_H #define RING_BUFFER_H //-----------------------------------------------------------------------------
namespace kernel { namespace ringb { struct CRingBuffer { typedef unsigned short size_type; typedef unsigned char value_type;
size_type readOffset_; size_type writeOffset_; size_type shadowOffset_; value_type *data_; size_type lastDataIndex_; }; //----------------------------------------------------------------------------- const struct CRingBuffer Create(CRingBuffer::value_type* const data, CRingBuffer::size_type capacity);
void Init(CRingBuffer* const rb, CRingBuffer::value_type* const data, CRingBuffer::size_type capacity);
CRingBuffer::size_type Read(CRingBuffer* const rb, CRingBuffer::value_type& value);
CRingBuffer::size_type ReadBuffer(CRingBuffer* const rb, CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize);
CRingBuffer::size_type Write(CRingBuffer* const rb, CRingBuffer::value_type value);
CRingBuffer::size_type WriteBuffer(CRingBuffer* const rb, const CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize); void Clear(CRingBuffer* const rb); CRingBuffer::size_type Capacity(CRingBuffer* const rb);
CRingBuffer::size_type Size(CRingBuffer* const rb); bool IsEmpty(CRingBuffer* const rb);
bool IsFull(CRingBuffer* const rb); void InitShadowRead(CRingBuffer* const rb);
CRingBuffer::size_type ShadowRead(CRingBuffer* const rb, CRingBuffer::value_type& value);
CRingBuffer::size_type ShadowReadBuffer(CRingBuffer* const rb, CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize); void ApplyShadowRead(CRingBuffer* const rb); bool IsShadowEmpty(CRingBuffer* const rb); } }
#endif //---------------------------------------------------------------------------
ring_buffer.cpp CODE #include "ring_buffer.h" #include <utility/assert.h> #include <string.h> //---------------------------------------------------------------------------
namespace kernel { namespace ringb { namespace tools { static inline CRingBuffer::size_type IncOffset(CRingBuffer::size_type offset, CRingBuffer::size_type lastDataIndex) { return (offset < lastDataIndex) ? offset + 1 : 0; } //--------------------------------------------------------------------------- static inline bool IsEmpty(CRingBuffer* const rb, CRingBuffer::size_type& offset) { SANITY_CHECK(rb); return offset == rb->writeOffset_; } //---------------------------------------------------------------------------
static inline CRingBuffer::size_type Read(CRingBuffer* const rb, CRingBuffer::size_type& offset, CRingBuffer::value_type& value) { SANITY_CHECK(rb); if (IsEmpty(rb, offset)) { return 0; } value = rb->data_[offset]; offset = tools::IncOffset(offset, rb->lastDataIndex_); return 1; } //---------------------------------------------------------------------------
static inline CRingBuffer::size_type ReadBuffer(CRingBuffer* const rb, CRingBuffer::size_type& offset, CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize) { if (IsEmpty(rb, offset)) { return 0; } if (rb->writeOffset_ > offset) { const CRingBuffer::size_type rbSize = rb->writeOffset_ - offset; const CRingBuffer::size_type readCount = (bufferSize > rbSize) ? rbSize : bufferSize; memcpy(buffer, rb->data_ + offset, readCount); offset += readCount; return readCount; } const CRingBuffer::size_type toEndCount = Capacity(rb) - offset; if (bufferSize > toEndCount) { memcpy(buffer, rb->data_ + offset, toEndCount); bufferSize -= toEndCount; const CRingBuffer::size_type readCount = (bufferSize > rb->writeOffset_) ? rb->writeOffset_ : bufferSize; memcpy(buffer + toEndCount, rb->data_, readCount); offset = readCount; return toEndCount + readCount; } memcpy(buffer, rb->data_ + offset, bufferSize); offset += bufferSize; return bufferSize; } } //--------------------------------------------------------------------------- const struct CRingBuffer CreateRingBuffer(CRingBuffer::value_type* const data, CRingBuffer::size_type capacity) { SANITY_CHECK(data && capacity); struct CRingBuffer result = { 0, 0, 0, data, capacity - 1 }; return result; } //---------------------------------------------------------------------------
void Init(CRingBuffer* const rb, CRingBuffer::value_type* const data, CRingBuffer::size_type capacity) { SANITY_CHECK(rb && data && capacity); rb->readOffset_ = 0; rb->writeOffset_ = 0; rb->shadowOffset_ = 0; rb->data_ = data; rb->lastDataIndex_ = capacity - 1; } //--------------------------------------------------------------------------- CRingBuffer::size_type Read(CRingBuffer* const rb, CRingBuffer::value_type& value) { SANITY_CHECK(rb); return tools::Read(rb, rb->readOffset_, value); } //---------------------------------------------------------------------------
CRingBuffer::size_type ReadBuffer(CRingBuffer* const rb, CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize) { SANITY_CHECK(rb); return tools::ReadBuffer(rb, rb->readOffset_, buffer, bufferSize); } //---------------------------------------------------------------------------
CRingBuffer::size_type Write(CRingBuffer* const rb, CRingBuffer::value_type value) { SANITY_CHECK(rb); if (IsFull(rb)) { return 0; } rb->data_[rb->writeOffset_] = value; rb->writeOffset_ = tools::IncOffset(rb->writeOffset_, rb->lastDataIndex_); return 1; } //---------------------------------------------------------------------------
CRingBuffer::size_type WriteBuffer(CRingBuffer* const rb, const CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize) { SANITY_CHECK(rb && buffer && bufferSize); if (IsFull(rb)) { return 0; } if (rb->writeOffset_ < rb->readOffset_) { const CRingBuffer::size_type toReadCount(rb->readOffset_ - rb->writeOffset_); const CRingBuffer::size_type writeCount = (toReadCount > bufferSize) ? bufferSize : toReadCount; memcpy(rb->data_ + rb->writeOffset_, buffer, writeCount); rb->writeOffset_ += writeCount; return writeCount; } const CRingBuffer::size_type toEndCount = Capacity(rb) - rb->writeOffset_; if (bufferSize > toEndCount) { memcpy(rb->data_ + rb->writeOffset_, buffer, toEndCount); bufferSize -= toEndCount;
const CRingBuffer::size_type writeCount = (bufferSize > rb->readOffset_) ? rb->readOffset_ : bufferSize;
memcpy(rb->data_, buffer + toEndCount, writeCount); rb->writeOffset_ = writeCount; return toEndCount + writeCount; } memcpy(rb->data_ + rb->writeOffset_, buffer, bufferSize); rb->writeOffset_ += bufferSize; return bufferSize; } //--------------------------------------------------------------------------- void Clear(CRingBuffer* const rb) { SANITY_CHECK(rb); rb->writeOffset_ = rb->readOffset_; } //--------------------------------------------------------------------------- CRingBuffer::size_type Capacity(CRingBuffer* const rb) { SANITY_CHECK(rb); return rb->lastDataIndex_ + 1; } //---------------------------------------------------------------------------
CRingBuffer::size_type Size(CRingBuffer* const rb) { SANITY_CHECK(rb); return (rb->readOffset_ > rb->writeOffset_) ? Capacity(rb) - rb->readOffset_ + rb->writeOffset_ : rb->writeOffset_ - rb->readOffset_ ; } //--------------------------------------------------------------------------- bool IsEmpty(CRingBuffer* const rb) { return tools::IsEmpty(rb, rb->readOffset_); } //---------------------------------------------------------------------------
bool IsFull(CRingBuffer* const rb) { SANITY_CHECK(rb); int cc = tools::IncOffset(rb->writeOffset_, rb->lastDataIndex_); return tools::IncOffset(rb->writeOffset_, rb->lastDataIndex_) == rb->readOffset_; } //--------------------------------------------------------------------------- void InitShadowRead(CRingBuffer* const rb) { SANITY_CHECK(rb); rb->shadowOffset_ = rb->readOffset_; } //---------------------------------------------------------------------------
CRingBuffer::size_type ShadowRead(CRingBuffer* const rb, CRingBuffer::value_type& value) { SANITY_CHECK(rb); return tools::Read(rb, rb->shadowOffset_, value); } //---------------------------------------------------------------------------
CRingBuffer::size_type ShadowReadBuffer(CRingBuffer* const rb, CRingBuffer::value_type* const buffer, CRingBuffer::size_type bufferSize) { SANITY_CHECK(rb); return tools::ReadBuffer(rb, rb->shadowOffset_, buffer, bufferSize); } //--------------------------------------------------------------------------- void ApplyShadowRead(CRingBuffer* const rb) { SANITY_CHECK(rb); rb->readOffset_ = rb->shadowOffset_; } //---------------------------------------------------------------------------
bool IsShadowEmpty(CRingBuffer* const rb) { return tools::IsEmpty(rb, rb->shadowOffset_); } //--------------------------------------------------------------------------- } }
пример использования: CODE int main(void) { usart::Init(); usart::handle_type usartHandle = usart::Open(usart::id0, AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT | AT91C_US_CHMODE_NORMAL, 115200);
unsigned char data(0); unsigned char data1(0); unsigned char wbuf[10] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA }; unsigned char rbuf[10] = { 0 }; int rCount = 0; while (1) { // usart::Write(usartHandle, 0xFF); // usart::WaitForData(usartHandle); // usart::Read(usartHandle, &data); rCount = 0; for (unsigned int i(0); i < 10; ++i) rbuf[i] = 0; usart::WriteBuffer(usartHandle, wbuf, 10); if (usart::IsError(usartHandle)) { usart::Flush(usartHandle); } usart::WaitForData(usartHandle); if (usart::IsError(usartHandle)) { usart::Flush(usartHandle); } while (rCount < 10) { usart::WaitForData(usartHandle); if (usart::IsError(usartHandle)) { usart::Flush(usartHandle); } rCount+= usart::ReadBuffer(usartHandle, rbuf + rCount, 10 - rCount); if (usart::IsError(usartHandle)) { usart::Flush(usartHandle); } } } }
|
|
|
|
|
 |
Ответов
|
Oct 12 2012, 13:28
|
Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418

|
Господа... Переписал драйвер... Теперь работает через PDC. Возникли следующие проблемы: 1) Для чтения использую буфер размером в два байта. Первый элемент помещаю в US_RPR , второй в US_RNPR. В прерывании ENDRX (RXBUFF), переписываю этот буфер в кольцевой буфер и заново инициализирую US_RPR, US_RNPR . Проблема в том, что при приеме теряются данные и выставляется флаг AT91C_US_OVRE... 2) Не знаю, насколько целесообразно использовать при передаче оба регистра US_TPR и US_TNPR 3) Если в я, в начале функции WriteBuffer запрещаю прерывание END_TX, а в конце разрешаю, то прерывание не срабатывает. Использовать функции типа __disable_irq() не хочется... Помогите решить, пожалуйста... CODE enum EUsartPDCMemoryChannel { USART_PDC_MC_0 = 0, USART_PDC_MC_1 = 1, USART_PDC_MC_COUNT }; typedef void (*FIrqHandlerCPtr)(void); struct CUsartInfo { id_type id_; // идентификатор usart AT91S_USART* usart_; // регистры usart FIrqHandlerCPtr irqHandler_; // обработчик прерываний usart size_type tprSize_; // размер передаваемого буфера в регистре-указателе памяти PDC size_type tnprSize_; // размер передаваемого буфера в регистре-указателе следующей памяти PDC token_type pdcRxBuffer_[USART_PDC_MC_COUNT]; // буффер для приема данных через PDC size_type pdcRxBufferIndex_; // индекс элемента буффера для приема данных через PDC, который в данный момент заполняется token_type txBuffer_[USART_TX_BUF_SIZE]; // буфер для передаваемой информации token_type rxBuffer_[USART_RX_BUF_SIZE]; // буфер для принимаемой информации struct kernel::ringb::CRingBuffer txRingBuffer_; // кольцевой буфер для передаваемой информации struct kernel::ringb::CRingBuffer rxRingBuffer_; // кольцевой буфер для принимаемой информации }; //--------------------------------------------------------------------------- static struct CUsartInfo usarts_[USART_ID_COUNT]; static status_type usartStatuses_[USART_ID_COUNT]; static const Pin usartPins_[] = { BOARD_PIN_USART_RXD, BOARD_PIN_USART_TXD, BOARD_PIN_USART_CTS, BOARD_PIN_USART_RTS }; //--------------------------------------------------------------------------- volatile unsigned int cc = 0; // обработчик прерывания usart inline void doIrqHandler(handle_type handle) { CUsartInfo* const info = &usarts_[handle]; unsigned int status = info->usart_->US_CSR; status &= info->usart_->US_IMR; // если произошла ошибка if ((status & USART_ST_HARDWARE_ERROR)) { usartStatuses_[handle] |= (status & USART_ST_HARDWARE_ERROR); info->usart_->US_CR = AT91C_US_RSTSTA; } // содержимое регистра US_TCR достигло 0 // (т.е. данные, содержащиеся в регистре-указателе памяти отправились) if (AT91C_US_ENDTX == (status & AT91C_US_ENDTX)) { // стираем из кольцевого буфера, переданный через PDC блок данных SANITY_CHECK(info->tprSize_ && info->tprSize_ <= kernel::ringb::SizeForRead(&info->txRingBuffer_));
kernel::ringb::Erase(&info->txRingBuffer_, info->tprSize_); info->tprSize_ = 0; // если, в регистре-указателе следующей памяти есть данные // if (info->usart_->US_TCR) // { // // то теперь они в регистре-указателе памяти и размер этих данных info->tnprSize_ // SANITY_CHECK(info->tnprSize_); // info->tprSize_ = info->tnprSize_; // info->tnprSize_ = 0; // } // если в кольцевом буфере есть не помещенные в PDC данные // if (info->tprSize_ < kernel::ringb::SizeForRead(&info->txRingBuffer_)) if (!kernel::ringb::IsEmpty(&info->txRingBuffer_)) { // SANITY_CHECK(info->tprSize_); // получаем из кольцевого буфера указатель на непрерывный блок данных token_type* txBuf = 0; kernel::ringb::size_type txBufSize = 0; kernel::ringb::ReadPersistentDataBlock(&info->txRingBuffer_, &txBuf, txBufSize, info->tprSize_); SANITY_CHECK(txBufSize);
// if (info->usart_->US_TCR) // { // // и помещаем этот блок-данных в регистр-указатель следующей памяти, // // так как регистр-указатель памяти уже содержит данные // info->tnprSize_ = txBufSize; // info->usart_->US_TNPR = (unsigned int)txBuf; // info->usart_->US_TNCR = txBufSize; // } // else // { info->tprSize_ = txBufSize; info->usart_->US_TPR = (unsigned int)txBuf; info->usart_->US_TCR = txBufSize; // } } // в случае, запрещаем прерывание AT91C_US_ENDTX //if (!info->tprSize_) else { info->usart_->US_IDR = AT91C_US_ENDTX; } } if (AT91C_US_RXBUFF == (status & AT91C_US_RXBUFF)) { // if (0 == info->usart_->US_RCR) // { if (USART_PDC_MC_COUNT > kernel::ringb::SizeForWrite(&info->rxRingBuffer_)) { usartStatuses_[handle] |= USART_ST_RX_BUF_OVERFLOW; } else { kernel::ringb::WriteBuffer(&info->rxRingBuffer_, info->pdcRxBuffer_, 2); // info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1; // kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]); // kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]); // info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1; // kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]); } info->usart_->US_RPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_0]; info->usart_->US_RCR = 1; info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_1]; info->usart_->US_RNCR = 1; info->pdcRxBufferIndex_ = 0; // } // else // { // if (kernel::ringb::IsFull(&info->rxRingBuffer_)) // { // usartStatuses_[handle] |= USART_ST_RX_BUF_OVERFLOW; // } // else // { // kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]); // } // info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[info->pdcRxBufferIndex_]; // info->usart_->US_RNCR = 1; // info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1; // } } } // обработчик прерываний для USART0 (AT91C_ID_US0) void IrqHandler0(void) { doIrqHandler(USART_ID_0); } // обработчик прерываний для USART1 (AT91C_ID_US1) void IrqHandler1(void) { doIrqHandler(USART_ID_1); } } //---------------------------------------------------------------------------
void Init(void) { PIO_Configure(tools::usartPins_, PIO_LISTSIZE(tools::usartPins_));
tools::usarts_[USART_ID_0].usart_ = AT91C_BASE_US0; tools::usarts_[USART_ID_0].id_ = AT91C_ID_US0; tools::usarts_[USART_ID_0].irqHandler_ = tools::IrqHandler0;
tools::usarts_[USART_ID_1].usart_ = AT91C_BASE_US1; tools::usarts_[USART_ID_1].id_ = AT91C_ID_US1; tools::usarts_[USART_ID_1].irqHandler_ = tools::IrqHandler1; for (token_type i(0); i < USART_ID_COUNT; ++i) { tools::usarts_[i].tprSize_ = 0; tools::usarts_[i].tnprSize_ = 0; tools::usarts_[i].pdcRxBufferIndex_ = 0;
kernel::ringb::Init(&tools::usarts_[i].txRingBuffer_, tools::usarts_[i].txBuffer_, USART_TX_BUF_SIZE); kernel::ringb::Init(&tools::usarts_[i].rxRingBuffer_, tools::usarts_[i].rxBuffer_, USART_RX_BUF_SIZE);
memset(tools::usarts_[i].pdcRxBuffer_, 0, tools::USART_PDC_MC_COUNT);
tools::usartStatuses_[i] = USART_ST_OK; } } //---------------------------------------------------------------------------
handle_type Open(const id_type usartId, const mode_type mode, const baudrate_type baudRate, const sync_frequency_type masterClockFrequency) { SANITY_CHECK(usartId < USART_ID_COUNT && baudRate && ((mode & AT91C_US_USMODE_ISO7816_0) != AT91C_US_USMODE_ISO7816_0) && ((mode & AT91C_US_USMODE_ISO7816_1) != AT91C_US_USMODE_ISO7816_1) && ((mode & AT91C_US_USMODE_IRDA) != AT91C_US_USMODE_IRDA)); tools::CUsartInfo* const info = &tools::usarts_[usartId];
kernel::ringb::Clear(&info->txRingBuffer_); kernel::ringb::Clear(&info->rxRingBuffer_); info->tprSize_ = 0; info->tnprSize_ = 0; info->pdcRxBufferIndex_ = 0;
PMC_EnablePeripheral(info->id_);
info->usart_->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA; info->usart_->US_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; info->usart_->US_MR = mode; if ((info->usart_->US_MR & AT91C_US_SYNC)) { info->usart_->US_BRGR = masterClockFrequency / baudRate; } else { const token_type freqSemplingMode = (info->usart_->US_MR & AT91C_US_OVER) ? 1 : 2; info->usart_->US_BRGR = masterClockFrequency / (8 * freqSemplingMode * baudRate); }
info->usart_->US_RPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_0]; info->usart_->US_RCR = 1; info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_1]; info->usart_->US_RNCR = 1; info->usart_->US_IER = AT91C_US_RXBUFF | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE; info->usart_->US_CR = AT91C_US_RXEN | AT91C_US_TXEN ; info->usart_->US_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
tools::usartStatuses_[usartId] = USART_ST_OK;
IRQ_ConfigureIT(info->id_, 0, info->irqHandler_); IRQ_EnableIT(info->id_); return usartId; } //--------------------------------------------------------------------------- bool IsError(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return tools::usartStatuses_[handle] != USART_ST_OK; } //--------------------------------------------------------------------------- status_type GetStatus(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return tools::usartStatuses_[handle]; } //--------------------------------------------------------------------------- bool IsInvalidHandle(const handle_type handle) { return handle >= USART_ID_COUNT; } //--------------------------------------------------------------------------- bool IsDataAvailableForReading(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle)); return !kernel::ringb::IsEmpty(&tools::usarts_[handle].rxRingBuffer_); } //--------------------------------------------------------------------------- void WaitForData(const handle_type handle) { SANITY_CHECK(!IsInvalidHandle(handle));
while (!IsDataAvailableForReading(handle)) { continue; } } //--------------------------------------------------------------------------- size_type Read(const handle_type handle, token_type* const data) { return ReadBuffer(handle, data, 1); } //--------------------------------------------------------------------------- size_type ReadBuffer(const handle_type handle, token_type* const buffer, const size_type bufferSize) { SANITY_CHECK(!IsInvalidHandle(handle) && buffer);
tools::CUsartInfo* const info = &tools::usarts_[handle]; if (!kernel::ringb::IsEmpty(&info->rxRingBuffer_)) { return kernel::ringb::ReadBuffer(&info->rxRingBuffer_, buffer, min(bufferSize, kernel::ringb::SizeForRead(&info->rxRingBuffer_))); } return 0; } //--------------------------------------------------------------------------- void Write(const handle_type handle, const token_type data) { WriteBuffer(handle, &data, 1); } //--------------------------------------------------------------------------- void WriteBuffer(const handle_type handle, const token_type* const buffer, const size_type bufferSize) { SANITY_CHECK(!IsInvalidHandle(handle));
if (!bufferSize) { return; } tools::CUsartInfo* const info = &tools::usarts_[handle]; if (kernel::ringb::IsFull(&info->txRingBuffer_) || bufferSize > kernel::ringb::SizeForWrite(&info->txRingBuffer_)) { tools::usartStatuses_[handle] |= USART_ST_TX_BUF_OVERFLOW; return; } kernel::ringb::WriteBuffer(&info->txRingBuffer_, buffer, bufferSize); // в регистре-указателе памяти нет данных (а в регистре-указателе следующей памяти и подавно) if (!info->usart_->US_TCR) { token_type* txBuf = 0; kernel::ringb::size_type txBufSize = 0; kernel::ringb::ReadPersistentDataBlock(&info->txRingBuffer_, &txBuf, txBufSize, 0); SANITY_CHECK(txBufSize); info->tprSize_ = txBufSize; info->usart_->US_TPR = (unsigned int)txBuf; info->usart_->US_TCR = txBufSize;
info->usart_->US_IER = AT91C_US_ENDTX; } } //---------------------------------------------------------------------------
|
|
|
|
Сообщений в этой теме
Parkan ARM 7 (at91sam7x) Драйвер для UART Oct 9 2012, 12:16 aaarrr Цитата(Parkan @ Oct 9 2012, 16:16) Написа... Oct 9 2012, 14:06 Parkan Цитата(aaarrr @ Oct 9 2012, 18:06) Учитыв... Oct 10 2012, 07:08  RabidRabbit Цитата(Parkan @ Oct 10 2012, 11:08) Если ... Oct 10 2012, 07:50  aaarrr Цитата(Parkan @ Oct 10 2012, 11:08) Еще в... Oct 10 2012, 07:50 Parkan Еще вопрос по PDC
В каждом канале PDC есть:
-регис... Oct 10 2012, 07:51 RabidRabbit Цитата(Parkan @ Oct 10 2012, 11:51) Тепер... Oct 10 2012, 07:56 aaarrr Цитата(Parkan @ Oct 10 2012, 11:51) Предп... Oct 10 2012, 07:56  Parkan Цитата(aaarrr @ Oct 10 2012, 11:56) Слома... Oct 10 2012, 09:08 Parkan И еще вопрос. Данные в uart можно передавать испол... Oct 10 2012, 08:06 RabidRabbit Цитата(Parkan @ Oct 10 2012, 12:06) И еще... Oct 10 2012, 08:12  Parkan Цитата(RabidRabbit @ Oct 10 2012, 12:12) ... Oct 10 2012, 08:44   RabidRabbit Цитата(Parkan @ Oct 10 2012, 12:44) Посмо... Oct 10 2012, 08:59    Parkan Цитата(RabidRabbit @ Oct 10 2012, 12:59) ... Oct 10 2012, 09:29     aaarrr Цитата(Parkan @ Oct 10 2012, 13:29) Разве... Oct 10 2012, 09:34     RabidRabbit Цитата(Parkan @ Oct 10 2012, 13:29) Ага, ... Oct 10 2012, 09:40 aaarrr Алгоритм передачи очень простой:
1. При появлении ... Oct 10 2012, 09:14 Parkan RabidRabbit, aaarrr спасибо Oct 10 2012, 09:50 aaarrr 1. Сделайте буферы большого размера и используйте ... Oct 12 2012, 14:34 Parkan Цитата(aaarrr @ Oct 12 2012, 18:34) 1. Сд... Oct 13 2012, 13:01  aaarrr Цитата(Parkan @ Oct 13 2012, 17:01) 2)Я н... Oct 13 2012, 14:13
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|