Autor Tema: Librería para implementar un Buffer Circular  (Leído 3406 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Librería para implementar un Buffer Circular
« en: 10 de Junio de 2010, 13:47:08 »
Hola

A raíz de estar trabajando en un reproductor MP3 con una memoria USB y un PIC24 necesité de una librería para implementar un buffer circular. En ese buffer se iba volcando el contenido del archivo MP3 y al mismo tiempo el códec VS1053B lo iba consumiendo. Lo conveniente era mantenerlo lleno para que la reproducción de audio no se entrecortara.

Estuve buscando la librería en línea y encontré la de Jarno Elonen en su página web:

Ring buffer streaming in general - how to implement
http://elonen.iki.fi/code/misc-notes/ringbuffer/

Sólo que está hecha en C++ y se controla como un objeto. Con varias modificaciones puede funcionar en C sencillo y opera correctamente. Con este buffer me fue posible leer datos desde la memoria USB a 320kbps sin pérdida de bytes.

Si no conocen los buffers circulares, acá hay una excelente guía al respecto.
http://en.wikipedia.org/wiki/Ring_buffer

Creo que es muy fácil de usar. La dejo adjunta.  :-/ Espero que les llegue a servir.

Código: [Seleccionar]
//Origen de la librería
//1997-06-19, Jarno Elonen <elonen<at>iki.fi> | URN:NBN:fi-fe20031153
//http://elonen.iki.fi/code/misc-notes/ringbuffer/

//Modificada a C sencillo por MigSantiago

//Prototipos de funciones
    void Create_Ring_Buffer(BYTE* buffer, unsigned int buffer_size);
    unsigned int Data_In( BYTE* data, unsigned int len );
    unsigned int Data_Out( BYTE* outData, unsigned int len );
    unsigned int SkipData( unsigned int len );
    unsigned int Free_Space();
    unsigned int Buffered_Bytes();
    void Update_State();

//Variables internas
unsigned char *m_load_ptr, *m_consume_ptr;
unsigned char *m_buff_end;
unsigned char *m_buff;
int m_max_load, m_max_consume, m_data_in_buffer;

//Funciones públicas
void Create_Ring_Buffer( BYTE* buffer, unsigned int buffer_size )
{
      m_buff = (unsigned char*)buffer;
m_buff_end = m_buff + buffer_size;
m_load_ptr = m_consume_ptr = m_buff;
m_max_load = buffer_size;
m_max_consume = m_data_in_buffer = 0;
Update_State();
}

// Try to add data to the buffer. After the call,
// 'len' contains the amount of bytes actually copied.
unsigned int Data_In( BYTE* data, unsigned int len )
{
if ( len > (unsigned int)m_max_load )
len = (unsigned int)m_max_load;
memcpy( m_load_ptr, data, len );
m_load_ptr += len;
m_data_in_buffer += len;
Update_State();
      return len;
}

// Request 'len' bytes from the buffer. After the call,
// 'len' contains the amount of bytes actually copied.
unsigned int Data_Out( BYTE* outData, unsigned int len )
{
if ( len > (unsigned int)m_max_consume )
len = (unsigned int)m_max_consume;
memcpy( outData, m_consume_ptr, len );
m_consume_ptr += len;
m_data_in_buffer -= len;
Update_State();
      return len;
}

// Tries to skip len bytes. After the call,
// 'len' contains the realized skip.
unsigned int SkipData( unsigned int len )
{
      int i;
      int skip;
unsigned int requestedSkip = len;
for (i=0; i<2; ++i ) // This may wrap  so try it twice
{
skip = (int)len;
if ( skip > m_max_consume )
skip = m_max_consume;
m_consume_ptr += skip;
m_data_in_buffer -= skip;
len -= skip;
Update_State();
}
len = requestedSkip - len;
      return len;
}

// The amount of data the buffer can currently receive on one Data_In() call.
unsigned int Free_Space()    { return (unsigned int)m_max_load; }

// The total amount of data in the buffer. Note that it may not be continuous: you may need
// two successive calls to Get_Data() to get it all.
unsigned int Buffered_Bytes() { return (unsigned int)m_data_in_buffer; }

//Funciones privadas
void Update_State()
{
if (m_consume_ptr == m_buff_end) m_consume_ptr = m_buff;
if (m_load_ptr == m_buff_end) m_load_ptr = m_buff;

if (m_load_ptr == m_consume_ptr)
{
if ( m_data_in_buffer > 0 )
{
m_max_load = 0;
m_max_consume = m_buff_end - m_consume_ptr;
}
else
{
m_max_load = m_buff_end - m_load_ptr;
m_max_consume = 0;
}
}
else if ( m_load_ptr > m_consume_ptr )
{
m_max_load = m_buff_end - m_load_ptr;
m_max_consume = m_load_ptr - m_consume_ptr;
}
else
{
m_max_load = m_consume_ptr - m_load_ptr;
m_max_consume = m_buff_end - m_consume_ptr;
}
}


Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Librería para implementar un Buffer Circular
« Respuesta #1 en: 10 de Junio de 2010, 16:20:55 »
Gracias, Santiago, muy interesante.  :mrgreen:
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Librería para implementar un Buffer Circular
« Respuesta #2 en: 10 de Junio de 2010, 17:23:06 »
No es complicarse?  :mrgreen: El buffer, 2 punteros (Escritura, lectura), un par de lineas y haces el Buffer circular   :undecided:


Saludos!  :mrgreen:
No contesto mensajes privados, las consultas en el foro

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Librería para implementar un Buffer Circular
« Respuesta #3 en: 10 de Junio de 2010, 21:09:04 »
Suky, bienvenido sea tu ejemplo. Yo escribí código pero no funcionaba bien. Este código me ofrece la ventaja de saber cuántos bytes puedo leer o escribir. Creo que no se complica usarlo, sólo copiar y pegar.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Librería para implementar un Buffer Circular
« Respuesta #4 en: 11 de Junio de 2010, 01:56:30 »
Nunca se me hubiera ocurrido buscar una librería para buffers circulares, siempre los he hecho a mano. Pero ahora que la veo, con esas funciones de control para saber el espacio ocupado y para liberar espacio, creo que realmente merece la pena. Gracias Santiago.

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Librería para implementar un Buffer Circular
« Respuesta #5 en: 11 de Junio de 2010, 14:04:42 »
Se ve muy interesante mig, gracias por publicarlo

Lo usarás con C30?

saludos.
.

Desconectado AKENAFAB

  • Colaborador
  • DsPIC30
  • *****
  • Mensajes: 3227
Re: Librería para implementar un Buffer Circular
« Respuesta #6 en: 11 de Junio de 2010, 16:04:09 »
 :mrgreen:

Yo creo que si  :mrgreen:

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Librería para implementar un Buffer Circular
« Respuesta #7 en: 11 de Junio de 2010, 17:11:19 »
Sí Cryn, ya está operando en C30.

Desconectado giff

  • PIC10
  • *
  • Mensajes: 31
    • Ignogantes
Re: Librería para implementar un Buffer Circular
« Respuesta #8 en: 17 de Junio de 2010, 00:54:02 »
gracias MigSantiago, amén!
Mi blog sobre apuntes de electrónica: www.ignogantes.net


 

anything