Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ARM 7 (at91sam7x) Драйвер для UART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Parkan
Приветствую, Благородные Доны и Донны.
Занимаюсь программированием микроконтроллеров недавно. Написал драйвер для 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);
}
}
}
}
aaarrr
Цитата(Parkan @ Oct 9 2012, 16:16) *
Написал драйвер для UART и надеюсь услышать критику и предложения.

Учитывая отсутствие буферизации в атмеловских UART'ах, драйвер без PDC имеет очень ограниченную область применения.
И зачем "тушить свет" при Parity или Framing error?
Parkan
Цитата(aaarrr @ Oct 9 2012, 18:06) *
Учитывая отсутствие буферизации в атмеловских UART'ах, драйвер без PDC имеет очень ограниченную область применения.

Здравствуйте.
Спасибо за ответ.
Наверное, Вы правы. В случае использования PDC мне непонятны следующие... Я хочу передать буфер через uart. В атмеловском примере это выглядит так:
CODE
unsigned char USART_WriteBuffer(
AT91S_USART *usart,
void *buffer,
unsigned int size)
{
// Check if the first PDC bank is free
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {

usart->US_TPR = (unsigned int) buffer;
usart->US_TCR = size;
usart->US_PTCR = AT91C_PDC_TXTEN;

return 1;
}
// Check if the second PDC bank is free
else if (usart->US_TNCR == 0) {

usart->US_TNPR = (unsigned int) buffer;
usart->US_TNCR = size;

return 1;
}
else {

return 0;
}
}

Неудобно здесь то, имхо, что функция сразу возвращает управление, т.е. если я передаю буфер размером в сто байт и скорость uart относительно маленькая, то в случае, если, после возвращения из функции я поменяю, скажем, 85 байт, то этот 85-ый байт (допустим, он еще не успел передаться) поменяется и в отправляемом сейчас буфере, что не здорово.
Предположим, я в функции write буду ждать, пока не окончится передача буфера и только потом верну управление. В этом случае получается не задействован регистр-указатель следующей передачи US_TNPR, что, наверное, не хорошо.
Еще вариант, что я копирую переданный буфер в свой и передаю pdc уже свой буфер, тогда pdc используется в "полном объеме" но тратится время на работу с промежуточным буфером....
Цитата(aaarrr @ Oct 9 2012, 18:06) *
И зачем "тушить свет" при Parity или Framing error?

Если происходит Parity или Framing error у меня почему-то начинает беспрерывно вызываться прерывание по этой ошибке. Как указать, что эта ошибка обработана, я не нашел. Если Вы мне подскажете, я буду Вам благодарен...
RabidRabbit
Цитата(Parkan @ Oct 10 2012, 11:08) *
Если происходит Parity или Framing error у меня почему-то начинает беспрерывно вызываться прерывание по этой ошибке. Как указать, что эта ошибка обработана, я не нашел. Если Вы мне подскажете, я буду Вам благодарен...

US_CR.RSTSTA не спасёт благородного дона?
aaarrr
Цитата(Parkan @ Oct 10 2012, 11:08) *
Еще вариант, что я копирую переданный буфер в свой и передаю pdc уже свой буфер, тогда pdc используется в "полном объеме" но тратится время на работу с промежуточным буфером....

Совершенно верно, использование PDC ведет к разрастанию буферизации. В случае UART это не очень критично, так как периферия по определению медленная.
Зато у процессора появляется возможность "отвлечься" на некоторое время.

Цитата(Parkan @ Oct 10 2012, 11:08) *
Если происходит Parity или Framing error у меня почему-то начинает беспрерывно вызываться прерывание по этой ошибке. Как указать, что эта ошибка обработана, я не нашел. Если Вы мне подскажете, я буду Вам благодарен...

Насколько я помню, ошибки сбрасываются по RSTSTA. Другое дело, что информативность того же Framing error в большинстве случаев близка к нулю - приложению эта информация может пригодиться разве что для статистики.
Parkan
Еще вопрос по PDC
В каждом канале PDC есть:
-регистр-указатель памяти;
-регистр-счетчик перемещения;
-регистр-указатель следующей памяти;
-регистр-счетчик следующего перемещения;

В примере от atmel
CODE
unsigned char USART_WriteBuffer(
AT91S_USART *usart,
void *buffer,
unsigned int size)
{
// Check if the first PDC bank is free
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {

usart->US_TPR = (unsigned int) buffer;
usart->US_TCR = size;
usart->US_PTCR = AT91C_PDC_TXTEN;

return 1;
}
// Check if the second PDC bank is free
else if (usart->US_TNCR == 0) {

usart->US_TNPR = (unsigned int) buffer;
usart->US_TNCR = size;

return 1;
}
else {

return 0;
}
}

проверяется свободность (посредством счетчики) регистра-указателя памяти и регистра-указателя следующей памяти, если они свободны то данные помещаются в регистр-указатель памяти. Иначе, проверяется свободность
регистра-указателя следующей памяти, если он свободен, то данные помещаются в него. Иначе, данные не передаются...
Теперь, собственно, вопрос...
Предположим, у нас заполнен регистра-указателя памяти и регистр-указатель следующей памяти. Через какое-то время данные из регистра указателя памяти передадутся и начнут передаваться данные из регистра-указателя следующей памяти. Что будет, если в этот момент в регистр- указатель памяти поместить новые данные?
RabidRabbit
Цитата(Parkan @ Oct 10 2012, 11:51) *
Теперь, собственно, вопрос...
Предположим, у нас заполнен регистра-указателя памяти и регистр-указатель следующей памяти. Через какое-то время данные из регистра указателя памяти передадутся и начнут передаваться данные из регистра-указателя следующей памяти. Что будет, если в этот момент в регистр- указатель памяти поместить новые данные?

По-моему, когда "данные из регистра указателя памяти передадутся", содержимое регистров "следующий" тупо (аппаратно) перепишется в "настоящий", а "следующий" таким же образом (аппаратно) обнулится, ну в примере от Atmel это вроде прозрачно... sm.gif
aaarrr
Цитата(Parkan @ Oct 10 2012, 11:51) *
Предположим, у нас заполнен регистра-указателя памяти и регистр-указатель следующей памяти. Через какое-то время данные из регистра указателя памяти передадутся и начнут передаваться данные из регистра-указателя следующей памяти. Что будет, если в этот момент в регистр- указатель памяти поместить новые данные?

Сломается передача, так как в TPR-TCR в этот момент уже будут значения, перенесенные из TNPR-TNCR.
Parkan
И еще вопрос. Данные в uart можно передавать используя PDС или регистр uart (US_THR). Что будет, если я начал передавать через PDC большой буфер данных ( условно: usart->US_TPR = (unsigned int) buffer; usart->US_TCR = size;) , а затем сразу записал символ в US_THR (usart->US_THR = c)?

Цитата(RabidRabbit @ Oct 10 2012, 11:50) *
US_CR.RSTSTA не спасёт благородного дона?

Хм... логично... спасибо... сглупил.

Цитата(aaarrr @ Oct 10 2012, 11:50) *
Совершенно верно, использование PDC ведет к разрастанию буферизации. В случае UART это не очень критично, так как периферия по определению медленная.
Зато у процессора появляется возможность "отвлечься" на некоторое время.


Насколько я помню, ошибки сбрасываются по RSTSTA. Другое дело, что информативность того же Framing error в большинстве случаев близка к нулю - приложению эта информация может пригодиться разве что для статистики.

Спасибо. Т.е. вы считаете, что надо использовать PDC в полном объеме и применять для этого собственный промежуточный буфер?

Цитата(aaarrr @ Oct 10 2012, 11:50) *
Совершенно верно, использование PDC ведет к разрастанию буферизации. В случае UART это не очень критично, так как периферия по определению медленная.
Зато у процессора появляется возможность "отвлечься" на некоторое время.


Насколько я помню, ошибки сбрасываются по RSTSTA. Другое дело, что информативность того же Framing error в большинстве случаев близка к нулю - приложению эта информация может пригодиться разве что для статистики.

Спасибо. Т.е., Вы считаете, что надо использовать PDC в полном объеме и применять для этого собственный промежуточный буфер?

Цитата(RabidRabbit @ Oct 10 2012, 11:56) *
По-моему, когда "данные из регистра указателя памяти передадутся", содержимое регистров "следующий" тупо (аппаратно) перепишется в "настоящий", а "следующий" таким же образом (аппаратно) обнулится, ну в примере от Atmel это вроде прозрачно... sm.gif

Благодарю
RabidRabbit
Цитата(Parkan @ Oct 10 2012, 12:06) *
И еще вопрос. Данные в uart можно передавать используя PDС или регистр uart (US_THR). Что будет, если я начал передавать через PDC большой буфер данных ( условно: usart->US_TPR = (unsigned int) buffer; usart->US_TCR = size;) , а затем сразу записал символ в US_THR (usart->US_THR = c)?

См. даташит, описание бита US_CSR.TXRDY.
зы: контроллер от этого взорваться не должен sm.gif

Parkan
Цитата(RabidRabbit @ Oct 10 2012, 12:12) *
См. даташит, описание бита US_CSR.TXRDY.


Посмотрел... Как я понял, при передачи через PDC устанавливается US_CSR.TXRDY в этом случае запись в US_THR не приведет ни к чему и записываемый символ будет потерян.

Цитата(RabidRabbit @ Oct 10 2012, 12:12) *
зы: контроллер от этого взорваться не должен sm.gif

Точно? sm.gif

RabidRabbit
Цитата(Parkan @ Oct 10 2012, 12:44) *
Посмотрел... Как я понял, при передачи через PDC устанавливается US_CSR.TXRDY в этом случае запись в US_THR не приведет ни к чему и записываемый символ будет потерян.

Ну, в моём понимании смысл похож, но всё немного по-другому sm.gif Стоящий бит US_CSR.TXRDY побуждает PDC закинуть байт в US_THR, и пока у PDC есть в наличии байты для отправки, US_CSR.TXRDY будет практически всё время лежать, а про лежачий бит US_CSR.TXRDY пишут, что "Writing a character in US_THR while TXRDY is low has no effect and the written character is lost.".
Parkan
Цитата(aaarrr @ Oct 10 2012, 11:56) *
Сломается передача, так как в TPR-TCR в этот момент уже будут значения, перенесенные из TNPR-TNCR.

С передачей через PDC связаны два прерывания ENDTX (возникает, когда PERIPH_TCR достигает 0), TXBUFE (возникает, когда PERIPH_TCR и PERIF_TNCR достигают 0).
По какому из этих прерываний я могу узнать, что можно записывать данные в регистр-указатель следующей памяти (что было бы логично на мой взгляд)? Т.е. предположим у меня есть три порции данных, первая помещена в регистр-указатель памяти PDC, вторая в регистр-указатель следующей памяти PDC, а третья пока висит во временном буфере. Хотелось бы при первой же возможности переместить эту третью порцию в PDC. И самый удачный момент, это когда в регистр-указатель памяти скопировалось значение из регистра указателя-следующей памяти (т.е. третья порция данных может быть помещена в освободившийся указатель-следующей памяти)
aaarrr
Алгоритм передачи очень простой:
1. При появлении данных разрешаем прерывание ENDTX.
2. В прерывании проверяем значение TCR. Если 0, то готовим два буфера и кладем их в TPR-TCR и TNPR-TNCR. Если не 0, то кладем один буфер в TNPR-TNCR.
То есть PDC окучиваем исключительно в прерывании. С приемом аналогично, только там немного сложнее из-за необходимости выгребать данные еще и по тайм-ауту.
Parkan
Цитата(RabidRabbit @ Oct 10 2012, 12:59) *
Ну, в моём понимании смысл похож, но всё немного по-другому sm.gif Стоящий бит US_CSR.TXRDY побуждает PDC закинуть байт в US_THR, и пока у PDC есть в наличии байты для отправки, US_CSR.TXRDY будет практически всё время лежать, а про лежачий бит US_CSR.TXRDY пишут, что "Writing a character in US_THR while TXRDY is low has no effect and the written character is lost.".


Ага, если PDC использует US_THR для передачи данных, тогда все понятно. Непонятно, чем PDC лучше, по сравнению с прямой записью в US_THR.
Как я понимаю, сакральный смысл PDC заключается в высвобождении процессора, дабы тот мог что-нибудь поделать полезное во время приема\передачи данных и, соответственно, осуществлении передачи данных из памяти в периферийные устройства и обратно без участия процессора. Это имеет смысл для многопоточных приложений или ОС. Однако, для однопоточной программы, PDC получается менее выгодный с точки зрения расхода памяти (нужна дополнительная буферизация) или объема вычислений (например, нужно организовывать цикл ожидания передачи данных (скорее всего бесконечный цикл, проверяющий флаг, того что передача данных через PDC завершена))?


Цитата(aaarrr @ Oct 10 2012, 13:14) *
Алгоритм передачи очень простой:
1. При появлении данных разрешаем прерывание ENDTX.
2. В прерывании проверяем значение TCR. Если 0, то готовим два буфера и кладем их в TPR-TCR и TNPR-TNCR. Если не 0, то кладем один буфер в TNPR-TNCR.
То есть PDC окучиваем исключительно в прерывании. С приемом аналогично, только там немного сложнее из-за необходимости выгребать данные еще и по тайм-ауту.

Разве, при возникновении прерывания TCR не всегда будет равно 0? ("ENDTX flag is set when the PERIPH_TCR register reaches zero")
aaarrr
Цитата(Parkan @ Oct 10 2012, 13:29) *
Разве, при возникновении прерывания TCR не всегда будет равно 0? ("ENDTX flag is set when the PERIPH_TCR register reaches zero")

Нет. ENDTX установится по достижении TCR нуля, но одновременно с этим TCR будет переписан значением из TNCR, если оно не нулевое.
RabidRabbit
Цитата(Parkan @ Oct 10 2012, 13:29) *
Ага, если PDC использует US_THR для передачи данных, тогда все понятно. Непонятно, чем PDC лучше, по сравнению с прямой записью в US_THR.

На мой взгляд, позволяет избавить процессор от лишнего нахождения в режиме IRQ. Тут уже вроде говорилось об этом. А если процессор не загружен обработкой прерываний, можно и не использовать PDC, никто не заставляет sm.gif

Цитата(Parkan @ Oct 10 2012, 13:29) *
Разве, при возникновении прерывания TCR не всегда будет равно 0? ("ENDTX flag is set when the PERIPH_TCR register reaches zero")

Только в случае, если на момент возникновения ENDTX регистр TNCR был пуст. Кстати, в даташите можно прочитать чуть далее, что "TXBUFE flag is set when both PERIPH_TCR and PERIPH_TNCR reach zero.".
Parkan
RabidRabbit, aaarrr спасибо
Parkan
Господа... Переписал драйвер... Теперь работает через 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;
}
}
//---------------------------------------------------------------------------
aaarrr
1. Сделайте буферы большого размера и используйте помимо ENDRX прерывание TIMEOUT.
2. Можно и не использовать, если выходной поток допускает разрывы.
3. А зачем запрещать ENDTX где-то еще, кроме самого прерывания?
Parkan
Цитата(aaarrr @ Oct 12 2012, 18:34) *
1. Сделайте буферы большого размера и используйте помимо ENDRX прерывание TIMEOUT.
2. Можно и не использовать, если выходной поток допускает разрывы.
3. А зачем запрещать ENDTX где-то еще, кроме самого прерывания?

Здравствуйте.
2)Я не понял, что значит "выходной поток допускает разрывы"... Вы имели ввиду, что без использования TNPR памяти будет переполнение буфера?
3) Если использовать регистр-указатель следующей памяти, то необходимо хранить в переменных текущие размеры передаваемых в TPR и в TNPR данных. Эти переменные будут изменяться в функции WriteBuffer и в обработчике прерываний, что может привести к некорректному поведению...
Т.е. с использованием TNPR я мыслил следующий алгоритм функции WriteBuffer
1) я записываю переданный буфер в кольцевой буфер.
2) далее проверяю TCR на 0 и TNCR на 0 (чтобы выполнялось одновременно), если верно, то помещаю в TPR блок данных из кольцевого буфера и сохраняю размер этого блока в переменной, скажем tprSize_
3) иначе проверяю TNCR на 0, если верно то помещаю в TNPR блок данных из кольцевого буфера и сохраняю размер этого блока в переменной, скажем tnpSize_. В момент когда я вошел в условие, но еще не поместил в TNPR данные происходит прерывание END_TX, в котором я также проверяю свободность кольцевого буфера и помещаю из него данные в PDC. В этом случае и возникает некорректная ситуация, заключающаяся в том, что я попытаюсь два раза одни и те же данные передать, сначала взяв их из буфера в прерывании, а затем взяв их из буфера получившей управление после прерывания функции WriteBuffer.
aaarrr
Цитата(Parkan @ Oct 13 2012, 17:01) *
2)Я не понял, что значит "выходной поток допускает разрывы"... Вы имели ввиду, что без использования TNPR памяти будет переполнение буфера?

Возможен простой передатчика, если процессор не может уйти в прерывание достаточно оперативно.

Цитата(Parkan @ Oct 13 2012, 17:01) *
3) Если использовать регистр-указатель следующей памяти, то необходимо хранить в переменных текущие размеры передаваемых в TPR и в TNPR данных. Эти переменные будут изменяться в функции WriteBuffer и в обработчике прерываний, что может привести к некорректному поведению...

Не нужно в функции WriteBuffer трогать регистры PDC:
1. Положили данные в FIFO
2. Разрешили прерывание ENDTX
Все остальное делается уже в обработчике прерывания.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.