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

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


Гуру
******

Группа: Свой
Сообщений: 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
RabidRabbit
сообщение Oct 10 2012, 09:40
Сообщение #17


Местный
***

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



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





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



RabidRabbit, aaarrr спасибо
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 12 2012, 13:28
Сообщение #19





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



Господа... Переписал драйвер... Теперь работает через PDC.
Возникли следующие проблемы:
1) Для чтения использую буфер размером в два байта. Первый элемент помещаю в US_RPR , второй в US_RNPR. В прерывании ENDRX (RXBUFF), переписываю этот буфер в кольцевой буфер и заново инициализирую US_RPR, US_RNPR . Проблема в том, что при приеме теряются данные и выставляется флаг AT91C_US_OVRE...
2) Не знаю, насколько целесообразно использовать при передаче оба регистра US_TPR и US_TNPR
3) Если в я, в начале функции WriteBuffer запрещаю прерывание END_TX, а в конце разрешаю, то прерывание не срабатывает. Использовать функции типа __disable_irq() не хочется...
Помогите решить, пожалуйста...
CODE
enum EUsartPDCMemoryChannel {
USART_PDC_MC_0 = 0,
USART_PDC_MC_1 = 1,
USART_PDC_MC_COUNT
};

typedef void (*FIrqHandlerCPtr)(void);

struct CUsartInfo
{
id_type id_; // идентификатор usart
AT91S_USART* usart_; // регистры usart
FIrqHandlerCPtr irqHandler_; // обработчик прерываний usart
size_type tprSize_; // размер передаваемого буфера в регистре-указателе памяти PDC
size_type tnprSize_; // размер передаваемого буфера в регистре-указателе следующей памяти PDC
token_type pdcRxBuffer_[USART_PDC_MC_COUNT]; // буффер для приема данных через PDC
size_type pdcRxBufferIndex_; // индекс элемента буффера для приема данных через PDC, который в данный момент заполняется
token_type txBuffer_[USART_TX_BUF_SIZE]; // буфер для передаваемой информации
token_type rxBuffer_[USART_RX_BUF_SIZE]; // буфер для принимаемой информации
struct kernel::ringb::CRingBuffer txRingBuffer_; // кольцевой буфер для передаваемой информации
struct kernel::ringb::CRingBuffer rxRingBuffer_; // кольцевой буфер для принимаемой информации
};
//---------------------------------------------------------------------------

static struct CUsartInfo usarts_[USART_ID_COUNT];
static status_type usartStatuses_[USART_ID_COUNT];
static const Pin usartPins_[] = {
BOARD_PIN_USART_RXD,
BOARD_PIN_USART_TXD,
BOARD_PIN_USART_CTS,
BOARD_PIN_USART_RTS
};
//---------------------------------------------------------------------------
volatile unsigned int cc = 0;
// обработчик прерывания usart
inline void doIrqHandler(handle_type handle)
{
CUsartInfo* const info = &usarts_[handle];

unsigned int status = info->usart_->US_CSR;
status &= info->usart_->US_IMR;

// если произошла ошибка
if ((status & USART_ST_HARDWARE_ERROR))
{
usartStatuses_[handle] |= (status & USART_ST_HARDWARE_ERROR);
info->usart_->US_CR = AT91C_US_RSTSTA;
}
// содержимое регистра US_TCR достигло 0
// (т.е. данные, содержащиеся в регистре-указателе памяти отправились)
if (AT91C_US_ENDTX == (status & AT91C_US_ENDTX))
{
// стираем из кольцевого буфера, переданный через PDC блок данных
SANITY_CHECK(info->tprSize_ && info->tprSize_ <= kernel::ringb::SizeForRead(&info->txRingBuffer_));

kernel::ringb::Erase(&info->txRingBuffer_, info->tprSize_);
info->tprSize_ = 0;

// если, в регистре-указателе следующей памяти есть данные
// if (info->usart_->US_TCR)
// {
// // то теперь они в регистре-указателе памяти и размер этих данных info->tnprSize_
// SANITY_CHECK(info->tnprSize_);
// info->tprSize_ = info->tnprSize_;
// info->tnprSize_ = 0;
// }
// если в кольцевом буфере есть не помещенные в PDC данные
// if (info->tprSize_ < kernel::ringb::SizeForRead(&info->txRingBuffer_))
if (!kernel::ringb::IsEmpty(&info->txRingBuffer_))
{
// SANITY_CHECK(info->tprSize_);

// получаем из кольцевого буфера указатель на непрерывный блок данных
token_type* txBuf = 0;
kernel::ringb::size_type txBufSize = 0;
kernel::ringb::ReadPersistentDataBlock(&info->txRingBuffer_,
&txBuf,
txBufSize,
info->tprSize_);

SANITY_CHECK(txBufSize);

// if (info->usart_->US_TCR)
// {
// // и помещаем этот блок-данных в регистр-указатель следующей памяти,
// // так как регистр-указатель памяти уже содержит данные
// info->tnprSize_ = txBufSize;
// info->usart_->US_TNPR = (unsigned int)txBuf;
// info->usart_->US_TNCR = txBufSize;
// }
// else
// {
info->tprSize_ = txBufSize;
info->usart_->US_TPR = (unsigned int)txBuf;
info->usart_->US_TCR = txBufSize;
// }
}
// в случае, запрещаем прерывание AT91C_US_ENDTX
//if (!info->tprSize_)
else
{
info->usart_->US_IDR = AT91C_US_ENDTX;
}
}
if (AT91C_US_RXBUFF == (status & AT91C_US_RXBUFF))
{
// if (0 == info->usart_->US_RCR)
// {
if (USART_PDC_MC_COUNT > kernel::ringb::SizeForWrite(&info->rxRingBuffer_))
{
usartStatuses_[handle] |= USART_ST_RX_BUF_OVERFLOW;
}
else
{
kernel::ringb::WriteBuffer(&info->rxRingBuffer_, info->pdcRxBuffer_, 2);
// info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1;
// kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]);
// kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]);
// info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1;
// kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]);
}
info->usart_->US_RPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_0];
info->usart_->US_RCR = 1;
info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_1];
info->usart_->US_RNCR = 1;
info->pdcRxBufferIndex_ = 0;
// }
// else
// {
// if (kernel::ringb::IsFull(&info->rxRingBuffer_))
// {
// usartStatuses_[handle] |= USART_ST_RX_BUF_OVERFLOW;
// }
// else
// {
// kernel::ringb::Write(&info->rxRingBuffer_, info->pdcRxBuffer_[info->pdcRxBufferIndex_]);
// }
// info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[info->pdcRxBufferIndex_];
// info->usart_->US_RNCR = 1;
// info->pdcRxBufferIndex_ = (info->pdcRxBufferIndex_ + 1) & 0x1;
// }
}
}
// обработчик прерываний для USART0 (AT91C_ID_US0)
void IrqHandler0(void)
{
doIrqHandler(USART_ID_0);
}

// обработчик прерываний для USART1 (AT91C_ID_US1)
void IrqHandler1(void)
{
doIrqHandler(USART_ID_1);
}
}
//---------------------------------------------------------------------------

void Init(void)
{
PIO_Configure(tools::usartPins_, PIO_LISTSIZE(tools::usartPins_));

tools::usarts_[USART_ID_0].usart_ = AT91C_BASE_US0;
tools::usarts_[USART_ID_0].id_ = AT91C_ID_US0;
tools::usarts_[USART_ID_0].irqHandler_ = tools::IrqHandler0;

tools::usarts_[USART_ID_1].usart_ = AT91C_BASE_US1;
tools::usarts_[USART_ID_1].id_ = AT91C_ID_US1;
tools::usarts_[USART_ID_1].irqHandler_ = tools::IrqHandler1;
for (token_type i(0); i < USART_ID_COUNT; ++i)
{
tools::usarts_[i].tprSize_ = 0;
tools::usarts_[i].tnprSize_ = 0;
tools::usarts_[i].pdcRxBufferIndex_ = 0;

kernel::ringb::Init(&tools::usarts_[i].txRingBuffer_,
tools::usarts_[i].txBuffer_,
USART_TX_BUF_SIZE);
kernel::ringb::Init(&tools::usarts_[i].rxRingBuffer_,
tools::usarts_[i].rxBuffer_,
USART_RX_BUF_SIZE);

memset(tools::usarts_[i].pdcRxBuffer_, 0, tools::USART_PDC_MC_COUNT);

tools::usartStatuses_[i] = USART_ST_OK;
}
}
//---------------------------------------------------------------------------

handle_type Open(const id_type usartId,
const mode_type mode,
const baudrate_type baudRate,
const sync_frequency_type masterClockFrequency)
{
SANITY_CHECK(usartId < USART_ID_COUNT
&& baudRate
&& ((mode & AT91C_US_USMODE_ISO7816_0) != AT91C_US_USMODE_ISO7816_0)
&& ((mode & AT91C_US_USMODE_ISO7816_1) != AT91C_US_USMODE_ISO7816_1)
&& ((mode & AT91C_US_USMODE_IRDA) != AT91C_US_USMODE_IRDA));

tools::CUsartInfo* const info = &tools::usarts_[usartId];

kernel::ringb::Clear(&info->txRingBuffer_);
kernel::ringb::Clear(&info->rxRingBuffer_);
info->tprSize_ = 0;
info->tnprSize_ = 0;
info->pdcRxBufferIndex_ = 0;

PMC_EnablePeripheral(info->id_);

info->usart_->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
info->usart_->US_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
info->usart_->US_MR = mode;
if ((info->usart_->US_MR & AT91C_US_SYNC))
{
info->usart_->US_BRGR = masterClockFrequency / baudRate;
}
else
{
const token_type freqSemplingMode = (info->usart_->US_MR & AT91C_US_OVER) ? 1 : 2;
info->usart_->US_BRGR = masterClockFrequency / (8 * freqSemplingMode * baudRate);
}

info->usart_->US_RPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_0];
info->usart_->US_RCR = 1;
info->usart_->US_RNPR = (unsigned int)&info->pdcRxBuffer_[tools::USART_PDC_MC_1];
info->usart_->US_RNCR = 1;

info->usart_->US_IER = AT91C_US_RXBUFF | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE;
info->usart_->US_CR = AT91C_US_RXEN | AT91C_US_TXEN ;
info->usart_->US_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;

tools::usartStatuses_[usartId] = USART_ST_OK;

IRQ_ConfigureIT(info->id_, 0, info->irqHandler_);
IRQ_EnableIT(info->id_);

return usartId;
}
//---------------------------------------------------------------------------

bool IsError(const handle_type handle)
{
SANITY_CHECK(!IsInvalidHandle(handle));
return tools::usartStatuses_[handle] != USART_ST_OK;
}
//---------------------------------------------------------------------------

status_type GetStatus(const handle_type handle)
{
SANITY_CHECK(!IsInvalidHandle(handle));
return tools::usartStatuses_[handle];
}
//---------------------------------------------------------------------------

bool IsInvalidHandle(const handle_type handle)
{
return handle >= USART_ID_COUNT;
}
//---------------------------------------------------------------------------

bool IsDataAvailableForReading(const handle_type handle)
{
SANITY_CHECK(!IsInvalidHandle(handle));
return !kernel::ringb::IsEmpty(&tools::usarts_[handle].rxRingBuffer_);
}
//---------------------------------------------------------------------------

void WaitForData(const handle_type handle)
{
SANITY_CHECK(!IsInvalidHandle(handle));

while (!IsDataAvailableForReading(handle))
{
continue;
}
}
//---------------------------------------------------------------------------

size_type Read(const handle_type handle,
token_type* const data)
{
return ReadBuffer(handle, data, 1);
}
//---------------------------------------------------------------------------

size_type ReadBuffer(const handle_type handle,
token_type* const buffer,
const size_type bufferSize)
{
SANITY_CHECK(!IsInvalidHandle(handle) && buffer);

tools::CUsartInfo* const info = &tools::usarts_[handle];
if (!kernel::ringb::IsEmpty(&info->rxRingBuffer_))
{
return kernel::ringb::ReadBuffer(&info->rxRingBuffer_, buffer,
min(bufferSize, kernel::ringb::SizeForRead(&info->rxRingBuffer_)));
}
return 0;
}
//---------------------------------------------------------------------------

void Write(const handle_type handle,
const token_type data)
{
WriteBuffer(handle, &data, 1);
}
//---------------------------------------------------------------------------

void WriteBuffer(const handle_type handle,
const token_type* const buffer,
const size_type bufferSize)
{
SANITY_CHECK(!IsInvalidHandle(handle));

if (!bufferSize)
{
return;
}

tools::CUsartInfo* const info = &tools::usarts_[handle];

if (kernel::ringb::IsFull(&info->txRingBuffer_)
|| bufferSize > kernel::ringb::SizeForWrite(&info->txRingBuffer_))
{
tools::usartStatuses_[handle] |= USART_ST_TX_BUF_OVERFLOW;
return;
}

kernel::ringb::WriteBuffer(&info->txRingBuffer_, buffer, bufferSize);
// в регистре-указателе памяти нет данных (а в регистре-указателе следующей памяти и подавно)
if (!info->usart_->US_TCR)
{
token_type* txBuf = 0;
kernel::ringb::size_type txBufSize = 0;
kernel::ringb::ReadPersistentDataBlock(&info->txRingBuffer_,
&txBuf,
txBufSize,
0);
SANITY_CHECK(txBufSize);
info->tprSize_ = txBufSize;
info->usart_->US_TPR = (unsigned int)txBuf;
info->usart_->US_TCR = txBufSize;

info->usart_->US_IER = AT91C_US_ENDTX;
}
}
//---------------------------------------------------------------------------
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Oct 12 2012, 14:34
Сообщение #20


Гуру
******

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



1. Сделайте буферы большого размера и используйте помимо ENDRX прерывание TIMEOUT.
2. Можно и не использовать, если выходной поток допускает разрывы.
3. А зачем запрещать ENDTX где-то еще, кроме самого прерывания?
Go to the top of the page
 
+Quote Post
Parkan
сообщение Oct 13 2012, 13:01
Сообщение #21





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



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


Гуру
******

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



Цитата(Parkan @ Oct 13 2012, 17:01) *
2)Я не понял, что значит "выходной поток допускает разрывы"... Вы имели ввиду, что без использования TNPR памяти будет переполнение буфера?

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

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

Не нужно в функции WriteBuffer трогать регистры PDC:
1. Положили данные в FIFO
2. Разрешили прерывание ENDTX
Все остальное делается уже в обработчике прерывания.
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:54
Рейтинг@Mail.ru


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