реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> ARM 7 (at91sam7x) Драйвер для UART
Parkan
сообщение Oct 9 2012, 12:16
Сообщение #1





Группа: Участник
Сообщений: 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);
}
}
}
}

Прикрепленные файлы
Прикрепленный файл  usart_ex.rar ( 4.33 килобайт ) Кол-во скачиваний: 14
 
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 9 2012, 14:06
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Parkan @ Oct 9 2012, 16:16) *
Написал драйвер для UART и надеюсь услышать критику и предложения.

Учитывая отсутствие буферизации в атмеловских UART'ах, драйвер без PDC имеет очень ограниченную область применения.
И зачем "тушить свет" при Parity или Framing error?
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 07:08
Сообщение #3





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



Цитата(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 у меня почему-то начинает беспрерывно вызываться прерывание по этой ошибке. Как указать, что эта ошибка обработана, я не нашел. Если Вы мне подскажете, я буду Вам благодарен...
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Oct 10 2012, 07:50
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



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

US_CR.RSTSTA не спасёт благородного дона?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 10 2012, 07:50
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



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

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

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

Насколько я помню, ошибки сбрасываются по RSTSTA. Другое дело, что информативность того же Framing error в большинстве случаев близка к нулю - приложению эта информация может пригодиться разве что для статистики.
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 07:51
Сообщение #6





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



Еще вопрос по 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;
}
}

проверяется свободность (посредством счетчики) регистра-указателя памяти и регистра-указателя следующей памяти, если они свободны то данные помещаются в регистр-указатель памяти. Иначе, проверяется свободность
регистра-указателя следующей памяти, если он свободен, то данные помещаются в него. Иначе, данные не передаются...
Теперь, собственно, вопрос...
Предположим, у нас заполнен регистра-указателя памяти и регистр-указатель следующей памяти. Через какое-то время данные из регистра указателя памяти передадутся и начнут передаваться данные из регистра-указателя следующей памяти. Что будет, если в этот момент в регистр- указатель памяти поместить новые данные?
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Oct 10 2012, 07:56
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



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

По-моему, когда "данные из регистра указателя памяти передадутся", содержимое регистров "следующий" тупо (аппаратно) перепишется в "настоящий", а "следующий" таким же образом (аппаратно) обнулится, ну в примере от Atmel это вроде прозрачно... sm.gif
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 10 2012, 07:56
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



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

Сломается передача, так как в TPR-TCR в этот момент уже будут значения, перенесенные из TNPR-TNCR.
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 08:06
Сообщение #9





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



И еще вопрос. Данные в 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

Благодарю
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Oct 10 2012, 08:12
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



Цитата(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

Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 08:44
Сообщение #11





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



Цитата(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

Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Oct 10 2012, 08:59
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



Цитата(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.".
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 09:08
Сообщение #13





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



Цитата(aaarrr @ Oct 10 2012, 11:56) *
Сломается передача, так как в TPR-TCR в этот момент уже будут значения, перенесенные из TNPR-TNCR.

С передачей через PDC связаны два прерывания ENDTX (возникает, когда PERIPH_TCR достигает 0), TXBUFE (возникает, когда PERIPH_TCR и PERIF_TNCR достигают 0).
По какому из этих прерываний я могу узнать, что можно записывать данные в регистр-указатель следующей памяти (что было бы логично на мой взгляд)? Т.е. предположим у меня есть три порции данных, первая помещена в регистр-указатель памяти PDC, вторая в регистр-указатель следующей памяти PDC, а третья пока висит во временном буфере. Хотелось бы при первой же возможности переместить эту третью порцию в PDC. И самый удачный момент, это когда в регистр-указатель памяти скопировалось значение из регистра указателя-следующей памяти (т.е. третья порция данных может быть помещена в освободившийся указатель-следующей памяти)
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 10 2012, 09:14
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Алгоритм передачи очень простой:
1. При появлении данных разрешаем прерывание ENDTX.
2. В прерывании проверяем значение TCR. Если 0, то готовим два буфера и кладем их в TPR-TCR и TNPR-TNCR. Если не 0, то кладем один буфер в TNPR-TNCR.
То есть PDC окучиваем исключительно в прерывании. С приемом аналогично, только там немного сложнее из-за необходимости выгребать данные еще и по тайм-ауту.
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 10 2012, 09:29
Сообщение #15





Группа: Участник
Сообщений: 12
Регистрация: 17-04-12
Пользователь №: 71 418



Цитата(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")

Сообщение отредактировал Parkan - Oct 10 2012, 09:32
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 22:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01574 секунд с 7
ELECTRONIX ©2004-2016