LINUX.ORG.RU

Raspberry Pi + UART (gpio) + прерывания

 , ,


0

1

Здравствуйте! Пытаюсь подключить Raspberry Pi к sim900. Для этого нужно настроить UART, используя прерывания. Облазил инет, не смог найти нужной инфы. Может у кого есть кусок кода на Си для чтения и записи UART Raspberry с использованием прерываний или подходящий пример. За помощь огромное спасибо.

Кстати, зачем там прерывания? Чем поллинг не устраивает?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Ядро 2015-05-05-raspbian-wheezy. Я на контроллере делал, так там куча библиотек с примерами, а здесь такого нет. Если есть какая инфа, то поделитесь по настройкам прерываний. Нужны прерывания, чтобы постоянно не опрашивать /dev/ttyAMA0.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

у тебя прерывание где висит-то? на gpio или через AMA* должно прилетать?

Я бы делал poll и не парился. Само проинформирует когда что-то появится на входе.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Eddy_Em

В примере приведено прерывание для gpio 17, я просматривал аналогичный материал, но сомневаюсь, что он будет работать для UART выводы 14 и 15. Там же нужно устанавливать соответствующие флаги.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Поллинг. Ничего сложного. С прерываниями, думаю, тоже можно разобраться, но все-таки поллинг — как-то попривычней, да и код будет как на «малинке», так и на «обычном ПК» работать.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Да, с наскока не возьмешь! Куда же теперь прицепить в него RX, TX. И как эта «беда» на их будет реагировать.

vash_sa
() автор топика
Ответ на: комментарий от Dark_SavanT

Похоже, хочет выполнить неблокирующее чтение с поллингом, но т.к. об этом ничего не знает, хочет гланды через задницу удалять — по прерыванию на ноге RTS считывать данные.

Т.с., вот функция, которая в течение 50мс ждет, есть ли что на входе, если нет — возвращает ноль. Использую, например, для работы с GPS-модулем. У тебя принцип тот же самый по сути...

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Dark_SavanT

Мне надо обрабатывать текстовые сообщения от sim900 о входящем звонке и СМС. Для этого необходимо создать обработчик прерываний, который при появлении в буфере RX данных, считывал бы текстовую информацию, отбрасывая \r \n.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

В контроллере у меня была функция проверяющая флаги

void uart_rx_irq()
{
static uint8_t rxdata;

/*
if (UART2_GetFlagStatus(UART2_FLAG_PE)) {
rxdata = UART2_ReceiveData8(); // Parity error flag
return;
}
*/

if (UART2_GetFlagStatus(UART2_FLAG_OR_LHE)) {
rxdata = UART2_ReceiveData8(); // clear Overrrun flag
return;
}
rxdata = UART2_ReceiveData8();

if (rxdata == LF) {
return;
}

if (rxdata == CR) {
if (uart_rx_count) {
if (OS_Bsem_Check(BS_UART)) {
OS_Bsem_Set(BS_UART_RESPONSE);
} else {
OS_Bsem_Set(BS_UART_TASK_RESPONSE);
}
}
return;
}

if (uart_rx_count < RX_BUFFER_SIZE) {
uart_rx_buffer[uart_rx_count] = rxdata;
++uart_rx_count;
}

}

Она срабатывала по наступлению события (прерыванию)

INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21)
{

uart_rx_irq();
}

Что-то подобное хотел сделать и здесь.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Это у тебя в мелкоконтроллерах не было никакой ОСи, а здесь ведро за тебя всю низкоуровневщину с прерываниями выполняет, тупо поллинг выполняй — и всē!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Спасибо! Я же не против. Я просто пока не догоняю как это сделать. Для меня пока полинг - это текст на непонятном мне языке. Если бы описание какое было! Как в нем сделать считывание UART и скидывание в буфер данных.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

считывание UART

UART - это файл в /dev. Вот и читай из него свои байты.

anonymous
()
Ответ на: комментарий от vash_sa

сначала - http://www.tldp.org/HOWTO/Serial-HOWTO.html

потом:

man 3 select

man 3 poll

Это то, что тебе нужно. Потом смотри в сторонцу libev сильно упростит написание софтины.

Dark_SavanT ★★★★★
()
Последнее исправление: Dark_SavanT (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

Если надо только обернуть дескриптор и ничего более - да. Если надо запилить асинхронную чтение/обработку/запись в несколько дескрипторов и это обмазать сверху таймерами - вот тут-то libev начинает становиться полезным.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

ХЗ, у меня даже и на таймеры есть свой механизм (volatile флаги + pthreads, а в потоке select):

volatile int tmout = 0;
pthread_t athread;
void *tmout_thread(void *buf){
    int selfd = -1, *sec = (int*)buf;
    struct timeval tv;
    tv.tv_sec  = *sec;
    tv.tv_usec = 0;
    errno = 0;
    while(selfd < 0){
        selfd = select(0, NULL, NULL, NULL, &tv);
        if(selfd < 0 && errno != EINTR){
            WARN(_("Error while select()"));
            tmout = 1;
            return NULL;
        }
    }
    tmout = 1;
    return NULL;
}
/**
 * run thread with pause [delay] (in seconds), at its end set variable tmout
 */
void set_timeout(int delay){
    static int run = 0;
    static int *arg = NULL;
    if(!arg) arg = MALLOC(int, 1);
    if(run && (pthread_kill(athread, 0) != ESRCH)){ // another timeout process detected - kill it
        pthread_cancel(athread);
        pthread_join(athread, NULL);
    }
    tmout = 0;
    run = 1;
    *arg = delay;
    if(pthread_create(&athread, NULL, tmout_thread, (void*)arg)){
        WARN(_("Can't create timeout thread!"));
        tmout = 1;
        return;
    }
    ;
}
char indi[] = "|/-\\";
char *iptr = indi;
#define WAIT_EVENT(evt, max_delay)  do{int __ = 0; set_timeout(max_delay); \
        PRINT(" "); while(!tmout && !evt){\
        sleep(1); if(!*(++iptr)) iptr = indi; if(++__%10==0) PRINT("\b. "); \
        PRINT("\b%c", *iptr);}; PRINT("\n");}while(0)

Как допилю штукенцию и узнаю у автора оригинала (который я уже перепилил до неузнаваемости), согласен ли он на GPLv3, выложу.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Dark_SavanT

Чо вы путаете ТСа, два идиота? Ему всего-то и надо что читать и писать в устройство. Не нужны там никакие прерывания, и, скорее всего ему даже делать это в отдельном потоке не нужно.

anonymous
()
Ответ на: комментарий от anonymous

А я ему с самого начала сказал, что тупого поллинга select'ом за глаза!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от anonymous

Это мы уже с эдиком за своё зацепились.

А так для ТС я скинул выше serial howto, его достаточно для работы с gsm-модулями.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

Спецы подсказали бы как читать по байтам выход uart и складывать в массив для анализа. Я привык к мелкоконтроллерам и размышляю в их терминах. А тут несколько отличается. Уже весь мозг вынес. А вы еще куски кода непонятного подкидываете. Если так все просто, то напишите пару строк.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Можно в Bash. Передать я там могу, а вот принять и отселектировать \r и \n проблема.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Я тебе дал ссылку на свою репу, там работа идет с GPS. Тебе тупо переделать командный интерфейс на GSM нужно. Ничего сложного.

Я привык к мелкоконтроллерам и размышляю в их терминах

Дык, там же та же самая хрень: заполняешь входной буфер до тех пор, пока не встретишь '\n', потом обрабатываешь. Если дошел до конца, а '\n' не встретил — обнуляешь нафиг (здесь же обнулять не надо — просто realloc делаешь).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от vash_sa

А вы еще куски кода непонятного подкидываете. Если так все просто, то напишите пару строк.

Попробуй как-то так:

  #include <stdio.h>
  int main ( void ){
    FILE *file = fopen ( "/dev/ttyAMA0", "r" );
    if ( file == NULL ){
      fprintf(stderr,"Cannot open file!\n");
      return -1;
    }
    char buffer[128];
    while( fgets(buffer, sizeof buffer, file) != NULL ){
    	buffer[strcspn(buffer, "\r\n")] = 0;
    	printf("Read: '%s'\n",buffer);   // doing comething with string, in this case simply pint it
    }
    fclose ( file );
    return 0;
  }

anonymous
()
Ответ на: комментарий от vash_sa

Я привык к мелкоконтроллерам и размышляю в их терминах. А тут несколько отличается.

Отличается. Весь низкоуровневый функционал для работы с устройством убран в драйвер ОС, который пользовательским программам представляет устройство как файл, который они и читают при наличии прав (кстати, проверь права на /dev/ttyAMA0). Ещё драйвер позволяет управлять режимом порта через ioctl, что позволяет тебе использовать setserial для установки параметром последовательного порта перед тем как гонять пример, приведённый выше. В принципе параметры порта ты можешь и из своей проги выставлять, про это читай «Serial How-To».

anonymous
()
Ответ на: комментарий от vash_sa
char buf;
int fd = open("/dev/ttyUSB0", O_RDWR);
int ret = read(fd, &buf, 1);

if( ret < 0 ){
    // error here
    exit(ret);
}

// do any sex what you want with buf value

Пардон, не ту доку сначала указал http://tldp.org/HOWTO/Serial-Programming-HOWTO/ Эту почтиай, она с примерами

Даже на русском http://linux.yaroslavl.ru/docs/howto/Serial-Programming/Serial-Programming-HO...

Dark_SavanT ★★★★★
()
Последнее исправление: Dark_SavanT (всего исправлений: 2)
Ответ на: комментарий от Eddy_Em

Дык, там же та же самая хрень: заполняешь входной буфер до тех пор, >пока не встретишь '\n', потом обрабатываешь. Если дошел до конца, а >'\n' не встретил — обнуляешь нафиг (здесь же обнулять не надо — >просто realloc делаешь).

Я смотрю в пример и не улавливаю где эта фраза реализована. Интересует только функция чтения. В функции записи все ясно.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa
 size_t read_tty(uint8_t *buff, size_t length){
	ssize_t L = 0;
	fd_set rfds;
	struct timeval tv;
	int retval;
	FD_ZERO(&rfds);
	FD_SET(comfd, &rfds);
	tv.tv_sec = 0; tv.tv_usec = 50000; // wait for 50ms
	retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
	if (!retval) return 0;
	if(FD_ISSET(comfd, &rfds)){
		if((L = read(comfd, buff, length)) < 1) return 0;
	}
	return (size_t)L;
} 
vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Здесь читается не больше length символов в буфер buff, а уж дальше ты можешь этому буферу хоть realloc делать, хоть что!

В конкретном примере я сделал проще: т.к. обычно сообщения не превышают от силы с полкилобайта, я для верности забульбенил килобайтный буфер и читаю в него:

uint8_t *get_portdata(){
	static uint8_t buf[1025];
	uint8_t *ptr = buf;
	size_t L = 0, rest = 1024;
	while(rest && (L = read_tty(ptr, rest))){
		rest -= L;
		ptr += L;
	}
	if(ptr != buf){
		*ptr = 0;
		ptr = buf;
	}else ptr = NULL;
	return ptr;
}
Если ты не уверен в длине, можешь либо проверять каждый раз, не кончается ли буфер '\n', либо реаллочить до тех пор, пока read_tty не вернет ноль (т.е. все данные считаны, а следующую порцию можно будет позже считать).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от vash_sa

Да, для пущей надежности таки стоит после возврата select'ом нуля проверить errno насичет EINTR (если отловлена эта ошибка, нужно заново запустить select с тем же tv).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Спасибо! У меня буфер был 512 и этого хватало для нормальной работы.

vash_sa
() автор топика
Ответ на: комментарий от anonymous

Я, конечно дико извиняюсь, но все-таки расшифруйте, пожалуйста, в какой строке и как выполняется проверка на наличие '\n' (0x0D). И как ее преобразовать, чтобы проверялось наличие '\r' (0x0A).

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Эдуард, подскажи ответ! Что-то я не догоняю.

vash_sa
() автор топика
Ответ на: комментарий от vash_sa

Я, конечно дико извиняюсь, но все-таки расшифруйте, пожалуйста, в какой строке и как выполняется проверка на наличие '\n' (0x0D). И как ее преобразовать, чтобы проверялось наличие '\r' (0x0A).

Первый же '\n' или '\r' заменяется кодом конца строки:

buffer[strcspn(buffer, "\r\n")] = 0;
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.