Занимаюсь программированием микроконтроллеров недавно. Написал драйвер для 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);
}
}
}
}