diff --git a/avr-threads/src/avr-thread-suspcont.c b/avr-threads/src/avr-thread-suspcont.c new file mode 100644 --- /dev/null +++ b/avr-threads/src/avr-thread-suspcont.c @@ -0,0 +1,98 @@ +// +// avr-thread-suspend/continue +// a very light weight thread synchronisation method +// +// Copyright 2009 R. mueller +// +// $Id:$ +// Rainer Mueller + +// Suspend and Continue of threads + +/* +This file is part of AVR-THREADS. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place, Suite +330, Boston, MA 02111-1307 USA + +Contact information: + +Dean Ferreyra +12902 Malena Drive +Santa Ana, CA 92705-1102 USA + +dean@octw.com +*/ + +#include +#include +#include +#include +#include "avr-thread-asm.h" +#include "avr-thread.h" +#include "avr-thread-def.h" + +/** +suspend the current thread + +\param thread pointer to context of suspended thread, + will set if it is not 0 +\param prepare function to be called after disabling the interrupt to finish + e.g. the interrupt enabling of a device + +*/ +void avr_thread_suspend( + volatile avr_thread_context** thread, //< ptr to context of suspended thread + void (*prepare)(void) //< setup function for e.g. device interrupt enable +) +{ + avr_thread_disable(); + + uint8_t sreg = SREG; + cli(); + + if (thread) { + *thread = avr_thread_active; + } + + if (prepare) { + (*prepare)(); + } + + // just wait and take a unique id for beeing suspended + avr_thread_active->waiting_for = (void*)avr_thread_continue; + avr_thread_active->state = ats_wait; + SREG = sreg; + avr_thread_switch(); +} + +void avr_thread_continue(volatile avr_thread_context* thread) +{ + avr_thread_disable(); + + uint8_t sreg = SREG; + cli(); + + if (thread->waiting_for != (void*)avr_thread_continue) { + SREG = sreg; + avr_thread_enable(); + return; + } + thread->waiting_for = 0; + thread->state &= ~ats_wait; + + SREG = sreg; + avr_thread_enable(); // thread switch will occur at end of the time slice +} diff --git a/avr-threads/src/avr-thread.h b/avr-threads/src/avr-thread.h --- a/avr-threads/src/avr-thread.h +++ b/avr-threads/src/avr-thread.h @@ -3,7 +3,7 @@ // // Copyright 2000, 2001, 2002, 2003, 2004 Dean Ferreyra // -// $Id$ +// $Id: avr-thread.h,v 1.3 2008-09-04 01:10:01 dean Exp $ // Dean Ferreyra // Threads for AVR. @@ -53,6 +53,7 @@ typedef enum { ats_normal, ats_wait, + ats_continue = 0x20, /* suspended --> wait for continue */ ats_clear = 0x40, ats_tick = 0x80 @@ -325,4 +326,43 @@ */ void avr_thread_isr_end(void); + + +/** +suspend the current thread + +The current thread will be marked as blocked (waiting for continue). +The first parameters gives information about the current thread context, which +is required for the avr_thread_continue()-call. +This parameter is useful, if you make a suspend within a function without +knowing which thread was calling. +Set this parameter to 0, if you dont't need this. + +The second parameter allows to do some initialisations without +interruptions. +Set this parameter to 0, if you dont't need this. + +\param thread pointer to context of suspended thread, + will set if it is not 0 +\param prepare function to be called after disabling the interrupt to finish + e.g. the interrupt enabling of a device + +*/ +void avr_thread_suspend( + volatile avr_thread_context** thread, //< ptr to context of suspended thread + void (*prepare)(void) //< setup function for e.g. device interrupt enable +); + +/** +continue a (suspended) thread + +The given thread will be marked as no longer suspended. A task switch will +occur at the end of the current time slice. +This allows a light weight process synchronisation. +You can call the continue function even from inside an interrupt service +routine. + +\param pointer to thread context of suspended thread +*/ +void avr_thread_continue(volatile avr_thread_context* thread); #endif diff --git a/avr-threads/src/rs232.c b/avr-threads/src/rs232.c new file mode 100644 --- /dev/null +++ b/avr-threads/src/rs232.c @@ -0,0 +1,183 @@ +/** **************************************************************** + +\brief RS232 access functions + +\file rs232.c +RS232 access functions + +Send and receive data from the rs232 port. +The access is done asynchronously in interrupt mode. +While transmission is pending, the calling thread is blocked. + +\dot +digraph G { + subgraph cluster0 { + node [shape=rect]; + label = "File: rs232.c"; + txisr[label="TXC ISR", shape=rect, style=filled, fillcolor=yellow]; + send_rs232 [shape=rect]; + send_buf[shape=ellipse, label="send_pointer\nsend_length"]; + send_rs232 -> send_buf [style=dashed]; + txisr -> send_buf [style=dashed]; + } + subgraph cluster1 { + node [shape=rect]; + label = "writer\n"; + any_funct[ shape=rect]; + } + any_funct->send_rs232; + send_rs232->any_funct[label="suspend"]; + txisr -> any_funct[label="continue"]; +} +\enddot + +\author R. Müller + +**/ + +#include +#include +#include +#include "avr-thread.h" +#include "global.h" // contains F_CPU ans some data types +#include "rs232.h" + +/*! +speed of the rs232 port */ +#define BAUDRATE 9600L + +static volatile avr_thread_context * suspended_writer = 0; +static int send_length; +static const char * send_pointer = 0; + +static volatile avr_thread_context * suspended_reader = 0; +static int recv_length = 0; +static char * recv_pointer = 0; + +/** +Receive interrupt service routine + +take the received byte and place it at the end of the receive buffer. +If no input request is pending, the received data is discarded +overwriting previous received data. This should not happen, since +the receiver interrupt is disabled while no data should be received. +*/ +ISR(USART_RXC_vect) +{ + if (recv_length > 0) + { + *recv_pointer = UDR; + recv_pointer ++; + recv_length --; + if (recv_length == 0) + { + UCSRB = UCSRB & ~0x80; // disable RXC Interrupt + recv_pointer = 0; + avr_thread_continue(suspended_reader); + } + } +} + +/** +transmit interrupt service routine + +Tranmit the next byte to the uart. +If all bytes were sent, the transmitter interrupt becomes disabled and +the calling thread will be continued. +*/ +ISR(USART_TXC_vect) +{ + + if (send_length == 0) + { + UCSRB = UCSRB & ~0x40; // disable TXC interrupt on last char + avr_thread_continue(suspended_writer); + } + else + { + // send next char from buffer or disable UDRIE-Bit + UDR = *send_pointer; + send_pointer ++; + send_length --; + } +} + +/** +setup the rs232 communication + +The parameters are fixed coded to 8 bite no parity, 1 stop bit. +The baud rate may be set by changing the corresponding define. +The transmitter and receiver of the avr will become enabled, +the corresponding interrupts are switched off. +*/ +void init_rs232(void) +{ + UCSRB |= (1<> 8); + + recv_length = 0; + send_length = 0; +} + + +static void prepare_send(void) +{ + UDR = *send_pointer; + send_pointer ++; + UCSRB = UCSRB | 0x40; // enable TXC interrupt +} +/** +Transmit the given data to the RS232 interface. + +The data will be sent to the interface. The function blocks the calling thread +until the last character will be signaled as transmitted. + +\note The data will be used directly. Don't change them while waiting! + +\param n number of bytes to send +\param data bytes to send + +*/ +void send_rs232(uint8 n, const char data[]) +{ + if (n > 0) + { + send_pointer = data; + send_length = n-1; + + avr_thread_suspend(&suspended_writer, prepare_send); + } +} + +static void prepare_recv(void) +{ + UCSRB = UCSRB | 0x80; // enable RXC Interrupt +} +/** +Receive bytes from the rs232 interface + +The function blocks, until the requested number of bytes were +received. + +\param n requested number of characters +\param data storage, where the received characters should be written to. + The buffer must be large enough! +\returns number of read characters +*/ +int recv_rs232(uint8 n, char * data) +{ + if (n > 0) + { + recv_pointer = data; + recv_length = n; + + avr_thread_suspend(&suspended_reader, prepare_recv); + } +} + +