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

 
 
> 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
 
Start new topic
Ответов
Parkan
сообщение Oct 10 2012, 08:06
Сообщение #2





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


Местный
***

Группа: Свой
Сообщений: 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
Сообщение #4





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


Местный
***

Группа: Свой
Сообщений: 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:29
Сообщение #6





Группа: Участник
Сообщений: 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
aaarrr
сообщение Oct 10 2012, 09:34
Сообщение #7


Гуру
******

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



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

Нет. ENDTX установится по достижении TCR нуля, но одновременно с этим TCR будет переписан значением из TNCR, если оно не нулевое.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Parkan   ARM 7 (at91sam7x) Драйвер для UART   Oct 9 2012, 12:16
- - aaarrr   Цитата(Parkan @ Oct 9 2012, 16:16) Написа...   Oct 9 2012, 14:06
|- - Parkan   Цитата(aaarrr @ Oct 9 2012, 18:06) Учитыв...   Oct 10 2012, 07:08
|- - RabidRabbit   Цитата(Parkan @ Oct 10 2012, 11:08) Если ...   Oct 10 2012, 07:50
|- - aaarrr   Цитата(Parkan @ Oct 10 2012, 11:08) Еще в...   Oct 10 2012, 07:50
- - Parkan   Еще вопрос по PDC В каждом канале PDC есть: -регис...   Oct 10 2012, 07:51
|- - RabidRabbit   Цитата(Parkan @ Oct 10 2012, 11:51) Тепер...   Oct 10 2012, 07:56
|- - aaarrr   Цитата(Parkan @ Oct 10 2012, 11:51) Предп...   Oct 10 2012, 07:56
|- - Parkan   Цитата(aaarrr @ Oct 10 2012, 11:56) Слома...   Oct 10 2012, 09:08
|- - RabidRabbit   Цитата(Parkan @ Oct 10 2012, 13:29) Ага, ...   Oct 10 2012, 09:40
- - aaarrr   Алгоритм передачи очень простой: 1. При появлении ...   Oct 10 2012, 09:14
- - Parkan   RabidRabbit, aaarrr спасибо   Oct 10 2012, 09:50
- - Parkan   RE: ARM 7 (at91sam7x) Драйвер для UART   Oct 12 2012, 13:28
- - aaarrr   1. Сделайте буферы большого размера и используйте ...   Oct 12 2012, 14:34
- - Parkan   Цитата(aaarrr @ Oct 12 2012, 18:34) 1. Сд...   Oct 13 2012, 13:01
- - aaarrr   Цитата(Parkan @ Oct 13 2012, 17:01) 2)Я н...   Oct 13 2012, 14:13


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

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 16:28
Рейтинг@Mail.ru


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