This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

problem with synchronization


  I'm working with eCos 1.3.1 in an ARM7TDMI processor

  I have written a little assembler routine to attend my serial IRQs (in
order to make a bug with the USART less harmful)
  The idea is to have a thread where I use these functions:
manda_buffer_enviar(buffer_pointer, length_of_the_buffer,
time_for_timeout);   // For sending
lee_buffer_recibido(buffer_pointer, length_of_the_buffer,
time_for_timeout);      // For receiving
  To send and receive (respectively) a stream through the serial line.

 I have made the USART produce a FIQ, so I use cyg_interrupt_set_vsr to
substitute the FIQ to my custom routine (to speed up serial transactions)
 I want to sleep the calling thread of these routines till the buffer is
full (when receiving) or it is empty (when sending), then the FIQ routine
should check if the buffer is full (or empty) and awake the thread.
 The FIQ simply sends or receives a character while it has space in the
buffer, when the buffer is full (or empty if it is transmitting) it
disables the generation of the FIQand should awake the thread that made the
call.

  I also want to set a timeout, in order to awake the thread if too much
time is spent without receiving (or sending) chars.
  I have implemented this with flags (timed flags) but it only works
correctly for the sending side, the receiving side doesn't set the timer
when I use cyg_flg_timed_wait, because it returns inmediatly returning
false.
  The courious thing is that it works coerrectly in the sending side, but
not in the receiving and both use the same method of sleeping and
awaking....

  I have tried to use, instead of flags, the pair cyg_thread_delay (in the
calling side) - cyg_thread_release (in the FIQ side), but this doesn't
work, I have tried to track what happens with this combination and I've
discover (don't know exactly how) that after calling cyg_thread_release my
main thread is exited !!!! (why does it suicide instead of awaking?)


  Please, take a look at the code and tell me if I'm doing something wrong.
I attach two files, vectors.S contains the code corresponding to the FIQ
routine, and seriel_FIQ.c contains the initialization routine, the calling
routines and the FIQ disabling routines.

  Do you suggest any other synchronization method?

  The FIQ calls termina_rutina_fiq_rx (termina_rutina_fiq_tx) when the
buffer is full (empty) if it is receiving (sending) data.  These routines
should awake the thread that has to process the serial data.

  To test I have used the following inside a lonely thread:

  inicializa_puerto_serie
  for (aux=1;aux<=20;aux++) {
     manda_buffer_enviar(prueba,aux,100);  // 1 second of timeout (ata
19200 bauds it is loooooong enough)
  }  // this works correctly
  for(aux=1;aux<=20;aux++) {
    lee_buffer_recibido(prueba,aux,300); // This doesn't wait till data
arraives at the serial port (and it should)
    manda_buffer_enviar(prueba,aux,100);  //This prints the buffer as it
was before calling lee_buffer_recibido.
 }


  I'm pretty sure that the FIQ routine is correctly programmed, because it
I don't make it awake the thread at the end of the FIQ (I let it awake by
timeout) it awakes correctly (so, the context is correctly saved). Besides,
the TRANSMITING side WORKS!!!










--
Rafael Rodríguez Velilla        rrv@tid.es
Telefónica I+D          http://www.tid.es
Telf: +34 - 91 337 4270


#include <pkgconf/hal_arm_mpp_tema.h>
#include <cyg/kernel/kapi.h> // Para sustituir la rutina de atención a la FIQ
#include <cyg/hal/mpp_tema_regs.h>
#include <cyg/hal/hal_io.h> //Para lo del HAL_WRITE... y amigos
#include <cyg/hal/serial_misc.h> 
#include <cyg/hal/hal_arch.h>

volatile cyg_uint8 *mpp_serial_buffer_recibido_punt_esc;
cyg_uint8 *mpp_serial_buffer_recibido_fin;
static 	 cyg_handle_t hilo_ligado_rx;
static   cyg_uint8 nada;

volatile cyg_uint8 *mpp_serial_buffer_enviar_punt_lec;
cyg_uint8 *mpp_serial_buffer_enviar_fin;
static cyg_handle_t hilo_ligado_tx;
static cyg_uint8 aviso[22]="No debo emitir nada\n"; 

volatile cyg_uint8 mpp_serial_bandera_overrun;

void cierra_puerto_serie_fiq(void)
{
  HAL_WRITE_UINT32 (MPP_US_IDR2,0xFFFFFFFF); //Disable all serial IRQs
  HAL_WRITE_UINT32 (MPP_FIQEnableClear,0x1); //Disable serial generating FIQ
}
extern cyg_VSR_t _asm_rutina_serie; //implementado en fiq.S

static cyg_flag_t tx_rx_completa;
static cyg_flag_t rx_completa;
#define TX_COMPLETA 0x1
#define LIMPIA_TX_COMPLETA 0xFFFFFFFE
#define RX_COMPLETA 0x1
#define LIMPIA_RX_COMPLETA 0xFFFFFFFE

void inicializa_puerto_serie_fiq(void)
{
  cyg_uint32 irfpri; 

  cyg_flag_init(&tx_rx_completa);  
  cyg_flag_init(&rx_completa);  

  hal_mpp_serial_init();
  HAL_WRITE_UINT32 (MPP_FIQEnableClear,0x1); //Disable FIQ
  HAL_READ_UINT32  (MPP_IRFPRI,irfpri);
  irfpri=irfpri | 0x2000; //Enable FIQ when USART2 raises an IRQ (IRQline 13)
  HAL_WRITE_UINT32 (MPP_IRFPRI,irfpri);

  HAL_WRITE_UINT32 (MPP_US_IDR2,0xFFFFFFFF); //Disable all USAR IRQs.
  HAL_WRITE_UINT32 (MPP_US_CR2,MPP_RXDIS_ESC|MPP_TXDIS_ESC); //Disable both 
							// serial RX and TX

  cyg_interrupt_set_vsr( CYGNUM_HAL_VECTOR_FIQ, &_asm_rutina_serie); 

  HAL_WRITE_UINT32 (MPP_FIQEnableSet,0x1); //Enable FIQ
}

cyg_uint8 USART8(cyg_uint8 convierteme)
//Routine to mend a bug with the USARTS
{
  cyg_uint8 resultado=0,aux=1,contador;
  for (aux=1,contador=1;contador<=8;aux=aux<<1,contador++)
  {
    if((convierteme&aux)!=0)
	resultado=resultado|(1<<(8-contador));
  }
  return(resultado);

}

cyg_uint8 lee_buffer_recibido(cyg_uint8 *buf,cyg_uint8 nlect,cyg_uint32 timeout)
{
  cyg_uint8 reason,aux;
  mpp_serial_buffer_recibido_punt_esc=buf;
  mpp_serial_buffer_recibido_fin=(buf+nlect);
  mpp_serial_bandera_overrun=0;
  hilo_ligado_rx=cyg_thread_self();

  cyg_flag_maskbits(&rx_completa,LIMPIA_RX_COMPLETA);

  HAL_WRITE_UINT32 (MPP_US_CR2, MPP_RSTSTA_ESC|MPP_RSTRX_ESC);
  HAL_WRITE_UINT32 (MPP_US_IER2, MPP_RXRDY_ESC); //Enable FIQ for RX.
  HAL_WRITE_UINT32 (MPP_US_CR2,MPP_RXEN_ESC);
  
  HAL_REORDER_BARRIER();
  cyg_flag_timed_wait(&rx_completa,RX_COMPLETA,CYG_FLAG_WAITMODE_OR,(cyg_tick_count_t) timeout);
  HAL_REORDER_BARRIER();
  cyg_flag_maskbits(&rx_completa,LIMPIA_RX_COMPLETA);
  HAL_REORDER_BARRIER();
  //cyg_thread_delay(timeout); // Se hecha a dormir con un timeout
  return nlect;
}

cyg_uint8 manda_buffer_enviar(cyg_uint8 *buf,cyg_uint8 nlect,cyg_uint32 timeout)
{
  cyg_uint8 reason,aux;

  mpp_serial_buffer_enviar_punt_lec=buf;
  mpp_serial_buffer_enviar_fin=(buf+nlect);
  hilo_ligado_tx=cyg_thread_self();

  for (aux=0;aux<nlect;aux++)
	*(buf+aux)=USART8(*(buf+aux));  // Prepare the buffer to counteract
					//USARTS' bug 
  cyg_flag_maskbits(&tx_rx_completa,LIMPIA_TX_COMPLETA);

  HAL_WRITE_UINT32 (MPP_US_CR2, MPP_RSTTX_ESC);
  HAL_WRITE_UINT32 (MPP_US_IER2, MPP_TXRDY_ESC); //Enable FIQ for TX.
  HAL_WRITE_UINT32 (MPP_US_CR2,MPP_TXEN_ESC);  // Enable TX
  
  cyg_flag_timed_wait(&tx_rx_completa,TX_COMPLETA,CYG_FLAG_WAITMODE_OR,timeout);
  for (aux=0;aux<nlect;aux++)
	*(buf+aux)=USART8(*(buf+aux));  // Correct buffer to counteract 
					//USARTS bug
  return nlect;
}


void termina_rutina_fiq_rx(void)
  // esto se ejecuta con las interrupciones inhibidas.
  // This is executed with both FIQ and IRQ disabled (in FIQ mode)
{
  HAL_WRITE_UINT32 (MPP_US_IDR2,MPP_RXRDY_ESC); //Disable FIQ for RX.
  HAL_WRITE_UINT32 (MPP_US_CR2,MPP_RXDIS_ESC);
  cyg_flag_setbits(&rx_completa,RX_COMPLETA);
  //cyg_thread_release(hilo_ligado_rx); 
}
void termina_rutina_fiq_tx(void)
  // esto se ejecuta con las interrupciones inhibidas.
  // This is executed with both FIQ and IRQ disabled (in FIQ mode)
{
  HAL_WRITE_UINT32 (MPP_US_IDR2,MPP_TXRDY_ESC); //Disable FIQ for RX.
  HAL_WRITE_UINT32 (MPP_US_CR2,MPP_TXDIS_ESC);
  //cyg_thread_release(hilo_ligado_tx); //Lo duerme con sleep_reason=DELAY
  cyg_flag_setbits(&tx_rx_completa,TX_COMPLETA);
}
	.extern mpp_serial_buffer_recibido_punt_esc
	.extern mpp_serial_buffer_recibido_fin
	.extern termina_rutina_fiq_rx

	.extern mpp_serial_buffer_enviar_punt_lec
	.extern mpp_serial_buffer_enviar_fin
	.extern termina_rutina_fiq_tx

	.extern mpp_serial_bandera_overrun
	.global _asm_rutina_serie
_asm_rutina_serie:
	sub	lr  , lr  , #4
	mov 	r8  , #MPP_BaseUSART2
	add 	r9  , r8  , #(MPP_US_CSR2-MPP_BaseUSART2)
	ldr 	r10 , [r9]
	ands 	r11 , r10  , #MPP_RXRDY_LEC
	beq	transmision 	// Jump if the RX IRQ isn't active
recepcion:
	ldr 	r12 , .mpp_serial_buffer_recibido_punt_esc 
	ldr 	r10 , [r12] // R10=place where I have to store what I receive
	add 	r11 , r8  , #(MPP_US_RHR2-MPP_BaseUSART2)
	ldr 	r11 , [r11] 	// Read data from serial port
	mov	r11 , r11, LSR #24 // Half-compensate USART's BUG
	strb	r11 , [r10]	// Store the resulting character
	add	r10 , r10 , #1  
	str	r10 , [r12]	// Increase the writting pointer
	ldr 	r11 , .mpp_serial_buffer_recibido_fin
	ldr 	r11 , [r11]	// Read the end of buffer pointer
	ldr	r12 , .mpp_serial_bandera_overrun
	ldrb	r12 , [r12]
	add	r10 , r10 , r12 // Add the overrun count to the number of
				//received chars
	cmp 	r10 , r11 	// Have we received all the expected chars?
	bhs	finrecepcion    // Yes=>then jump
finrx:
	ldr 	r10 , [r9]  // Read again the USART's alarm
overrun:
	ands	r10 , r10 , #MPP_OVRE_LEC
	beq	finoverrun  //Jump if the overrun flag is not set
	ldr	r10 , .mpp_serial_bandera_overrun
	ldrb	r11 , [r10]
	add	r11 , r11 , #1
	strb	r11 , [r10]
	mov	r12 , #MPP_RSTSTA_ESC
	str	r12 , [r8]	// Lower the overrun flag
finoverrun:
	movs	pc  , lr // END OF FIQ
transmision:
	ands	r11 , r10 , #MPP_TXRDY_LEC
	beq	fintx
	ldr 	r10 , .mpp_serial_buffer_enviar_punt_lec
	ldr 	r11 , [r10]  	// Load address of the byte to be sent
	ldrb	r12 , [r11]  	// Load the byte to send
	mov 	r12 , r12 , LSL #11 //Shift to counteract part of USART's bug
	add	r10 , r8 , #(MPP_US_THR2-MPP_BaseUSART2)
	str 	r12 , [r10]  	// Send the character through the serial line
	add	r11 , r11, #1  	// Increase the pointer of the read char
	ldr 	r10 , .mpp_serial_buffer_enviar_punt_lec
	str	r11 , [r10]	// Store it for the next FIQ
	ldr	r12 , .mpp_serial_buffer_enviar_fin
	ldr	r12 , [r12]
	cmp	r12 , r11 	// Have I sent all the chars of the buffer?
	beq	fintransmision  // YES=> jump
fintx:
	movs	pc  , lr // END OF FIQ
PTR(vuelve_de_termina_rutina_fiq_rx)
PTR(mpp_serial_buffer_recibido_punt_esc)
PTR(mpp_serial_buffer_recibido_fin)
PTR(termina_rutina_fiq_rx)

PTR(vuelve_de_termina_rutina_fiq_tx)
PTR(mpp_serial_buffer_enviar_punt_lec)
PTR(mpp_serial_buffer_enviar_fin)
PTR(termina_rutina_fiq_tx)

PTR(mpp_serial_bandera_overrun)
PTR(salvaguarda_de_R0)
PTR(__rutina_serie_rx_stack)
PTR(__rutina_serie_tx_stack)
finrecepcion:
	ldr 	sp,.__rutina_serie_rx_stack
	mrs	r8 , spsr
	stmfd	sp!,{r0-r3,r8,lr}  //save part of the context 
	ldr	lr , .vuelve_de_termina_rutina_fiq_rx 
	ldr	pc , .termina_rutina_fiq_rx // Maybe a thread switch will happen
vuelve_de_termina_rutina_fiq_rx:
	ldmfd	sp!,{r0-r3,r8,lr} //Restore the saved registers
	msr	spsr , r8
	movs 	pc,lr	// END OF FIQ

fintransmision:
	ldr 	sp,.__rutina_serie_tx_stack
	mrs	r8 , spsr
	stmfd	sp!,{r0-r3,r8,lr}  //save part of the context 
	ldr	lr , .vuelve_de_termina_rutina_fiq_tx 
	ldr	pc , .termina_rutina_fiq_tx //A thread-switch may happen
vuelve_de_termina_rutina_fiq_tx:
	ldmfd	sp!,{r0-r3,r8,lr} //Restore the saved registers
	msr	spsr , r8
	movs 	pc,lr	// END OF FIQ

// RAFA, RUTINA SERIE
...
...

// RAFA, RUTINA SERIE
	.section bss
	.balign 32
salvaguarda_de_R0:
	.long 0
	.long 0
	.rept	1000
	.long	0
	.endr
__rutina_serie_rx_stack:
	.rept	1000
	.long	0
	.endr
__rutina_serie_tx_stack:
// RAFA, RUTINA SERIE

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]