2014-10-26 16:18:04 -03:00
# include <AP_HAL.h>
# if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_NAVIO
2015-04-16 12:18:14 -03:00
# include "GPIO.h"
2014-10-26 16:18:04 -03:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <stdint.h>
# include <sys/ioctl.h>
2015-04-16 12:18:14 -03:00
# include <pthread.h>
# include <string.h>
# include <errno.h>
# include <stdint.h>
# include <time.h>
# include <sys/time.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/mman.h>
# include <assert.h>
2014-10-26 16:18:04 -03:00
# include "RCInput_Navio.h"
2015-04-16 12:18:14 -03:00
//Parametres
# define RCIN_NAVIO_BUFFER_LENGTH 8
# define RCIN_NAVIO_SAMPLE_FREQ 500
# define RCIN_NAVIO_DMA_CHANNEL 0
# define RCIN_NAVIO_MAX_COUNTER 1300
# define PPM_INPUT_NAVIO RPI_GPIO_4
# define RCIN_NAVIO_MAX_SIZE_LINE 50
//Memory Addresses
# define RCIN_NAVIO_RPI1_DMA_BASE 0x20007000
# define RCIN_NAVIO_RPI1_CLK_BASE 0x20101000
# define RCIN_NAVIO_RPI1_PCM_BASE 0x20203000
# define RCIN_NAVIO_RPI2_DMA_BASE 0x3F007000
# define RCIN_NAVIO_RPI2_CLK_BASE 0x3F101000
# define RCIN_NAVIO_RPI2_PCM_BASE 0x3F203000
# define RCIN_NAVIO_GPIO_LEV0_ADDR 0x7e200034
# define RCIN_NAVIO_DMA_LEN 0x1000
# define RCIN_NAVIO_CLK_LEN 0xA8
# define RCIN_NAVIO_PCM_LEN 0x24
# define RCIN_NAVIO_TIMER_BASE 0x7e003004
# define RCIN_NAVIO_DMA_SRC_INC (1<<8)
# define RCIN_NAVIO_DMA_DEST_INC (1<<4)
# define RCIN_NAVIO_DMA_NO_WIDE_BURSTS (1<<26)
# define RCIN_NAVIO_DMA_WAIT_RESP (1<<3)
# define RCIN_NAVIO_DMA_D_DREQ (1<<6)
# define RCIN_NAVIO_DMA_PER_MAP(x) ((x)<<16)
# define RCIN_NAVIO_DMA_END (1<<1)
# define RCIN_NAVIO_DMA_RESET (1<<31)
# define RCIN_NAVIO_DMA_INT (1<<2)
# define RCIN_NAVIO_DMA_CS (0x00 / 4)
# define RCIN_NAVIO_DMA_CONBLK_AD (0x04 / 4)
# define RCIN_NAVIO_DMA_DEBUG (0x20 / 4)
# define RCIN_NAVIO_PCM_CS_A (0x00 / 4)
# define RCIN_NAVIO_PCM_FIFO_A (0x04 / 4)
# define RCIN_NAVIO_PCM_MODE_A (0x08 / 4)
# define RCIN_NAVIO_PCM_RXC_A (0x0c / 4)
# define RCIN_NAVIO_PCM_TXC_A (0x10 / 4)
# define RCIN_NAVIO_PCM_DREQ_A (0x14 / 4)
# define RCIN_NAVIO_PCM_INTEN_A (0x18 / 4)
# define RCIN_NAVIO_PCM_INT_STC_A (0x1c / 4)
# define RCIN_NAVIO_PCM_GRAY (0x20 / 4)
# define RCIN_NAVIO_PCMCLK_CNTL 38
# define RCIN_NAVIO_PCMCLK_DIV 39
2014-10-26 16:18:04 -03:00
extern const AP_HAL : : HAL & hal ;
using namespace Linux ;
2015-04-16 12:18:14 -03:00
volatile uint32_t * LinuxRCInput_Navio : : pcm_reg ;
volatile uint32_t * LinuxRCInput_Navio : : clk_reg ;
volatile uint32_t * LinuxRCInput_Navio : : dma_reg ;
Memory_table : : Memory_table ( )
2014-10-26 16:18:04 -03:00
{
2015-04-16 12:18:14 -03:00
_page_count = 0 ;
}
//Init Memory table
Memory_table : : Memory_table ( uint32_t page_count , int version )
{
uint32_t i ;
int fdMem , file ;
//Cache coherent adresses depends on RPI's version
uint32_t bus = version = = 1 ? 0x40000000 : 0xC0000000 ;
uint64_t pageInfo ;
void * offset ;
_virt_pages = ( void * * ) malloc ( page_count * sizeof ( void * ) ) ;
_phys_pages = ( void * * ) malloc ( page_count * sizeof ( void * ) ) ;
_page_count = page_count ;
if ( ( fdMem = open ( " /dev/mem " , O_RDWR | O_SYNC ) ) < 0 ) {
fprintf ( stderr , " Failed to open /dev/mem \n " ) ;
exit ( - 1 ) ;
}
if ( ( file = open ( " /proc/self/pagemap " , O_RDWR | O_SYNC ) ) < 0 ) {
fprintf ( stderr , " Failed to open /proc/self/pagemap \n " ) ;
exit ( - 1 ) ;
}
//Magic to determine the physical address for this page:
offset = mmap ( 0 , _page_count * PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE | MAP_LOCKED , - 1 , 0 ) ;
lseek ( file , ( ( uint32_t ) offset ) / PAGE_SIZE * 8 , SEEK_SET ) ;
//Get list of available cache coherent physical addresses
for ( i = 0 ; i < _page_count ; i + + ) {
_virt_pages [ i ] = mmap ( 0 , PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE | MAP_LOCKED , - 1 , 0 ) ;
: : read ( file , & pageInfo , 8 ) ;
_phys_pages [ i ] = ( void * ) ( ( uint32_t ) ( pageInfo * PAGE_SIZE ) | bus ) ;
}
//Map physical addresses to virtual memory
for ( i = 0 ; i < _page_count ; i + + ) {
munmap ( _virt_pages [ i ] , PAGE_SIZE ) ;
_virt_pages [ i ] = mmap ( _virt_pages [ i ] , PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_FIXED | MAP_NORESERVE | MAP_LOCKED , fdMem , ( ( uint32_t ) _phys_pages [ i ] & ( version = = 1 ? 0xFFFFFFFF : ~ bus ) ) ) ;
memset ( _virt_pages [ i ] , 0xee , PAGE_SIZE ) ;
}
close ( file ) ;
close ( fdMem ) ;
}
Memory_table : : ~ Memory_table ( )
{
free ( _virt_pages ) ;
free ( _phys_pages ) ;
}
2015-07-01 09:04:57 -03:00
// This function returns physical address with help of pointer, which is offset from the beginning of the buffer.
void * Memory_table : : get_page ( void * * const pages , uint32_t addr ) const
2015-04-16 12:18:14 -03:00
{
2015-07-01 09:04:57 -03:00
if ( addr > = PAGE_SIZE * _page_count ) {
return NULL ;
2015-04-16 12:18:14 -03:00
}
2015-07-01 09:04:57 -03:00
return ( uint8_t * ) pages [ ( uint32_t ) addr / 4096 ] + addr % 4096 ;
2015-04-16 12:18:14 -03:00
}
2015-07-01 09:04:57 -03:00
//Get virtual address from the corresponding physical address from memory_table.
void * Memory_table : : get_virt_addr ( const uint32_t phys_addr ) const
2015-04-16 12:18:14 -03:00
{
2015-07-01 09:04:57 -03:00
// FIXME: Can't the address be calculated directly?
// FIXME: if the address room in _phys_pages is not fragmented one may avoid a complete loop ..
uint32_t i = 0 ;
for ( ; i < _page_count ; i + + ) {
2015-04-16 12:18:14 -03:00
if ( ( uint32_t ) _phys_pages [ i ] = = ( ( ( uint32_t ) phys_addr ) & 0xFFFFF000 ) ) {
2015-07-01 09:04:57 -03:00
return ( void * ) ( ( uint32_t ) _virt_pages [ i ] + ( phys_addr & 0xFFF ) ) ;
2015-04-16 12:18:14 -03:00
}
}
return NULL ;
}
2015-07-01 09:04:57 -03:00
// FIXME: in-congruent function style see above
2015-04-16 12:18:14 -03:00
// This function returns offset from the beginning of the buffer using virtual address and memory_table.
2015-07-01 09:04:57 -03:00
uint32_t Memory_table : : get_offset ( void * * const pages , const uint32_t addr ) const
2015-04-16 12:18:14 -03:00
{
2015-07-01 09:04:57 -03:00
uint32_t i = 0 ;
for ( ; i < _page_count ; i + + ) {
if ( ( uint32_t ) pages [ i ] = = ( addr & 0xFFFFF000 ) ) {
return ( i * PAGE_SIZE + ( addr & 0xFFF ) ) ;
2015-04-16 12:18:14 -03:00
}
}
return - 1 ;
}
//How many bytes are available for reading in circle buffer?
2015-07-01 09:04:57 -03:00
uint32_t Memory_table : : bytes_available ( const uint32_t read_addr , const uint32_t write_addr ) const
2015-04-16 12:18:14 -03:00
{
if ( write_addr > read_addr ) {
2015-07-01 09:04:57 -03:00
return ( write_addr - read_addr ) ;
2015-04-16 12:18:14 -03:00
}
else {
2015-07-01 09:04:57 -03:00
return _page_count * PAGE_SIZE - ( read_addr - write_addr ) ;
2015-04-16 12:18:14 -03:00
}
}
2015-07-01 09:04:57 -03:00
uint32_t Memory_table : : get_page_count ( ) const
2015-04-16 12:18:14 -03:00
{
return _page_count ;
}
// More memory mapping
int get_raspberry_pi_version ( )
{
char buffer [ RCIN_NAVIO_MAX_SIZE_LINE ] ;
const char * hardware_description_entry = " Hardware " ;
const char * v1 = " BCM2708 " ;
const char * v2 = " BCM2709 " ;
char * flag ;
FILE * fd ;
fd = fopen ( " /proc/cpuinfo " , " r " ) ;
while ( fgets ( buffer , RCIN_NAVIO_MAX_SIZE_LINE , fd ) ! = NULL ) {
flag = strstr ( buffer , hardware_description_entry ) ;
if ( flag ! = NULL ) {
if ( strstr ( buffer , v2 ) ! = NULL ) {
printf ( " Raspberry Pi 2 with BCM2709! \n " ) ;
fclose ( fd ) ;
return 2 ;
}
else if ( strstr ( buffer , v1 ) ! = NULL ) {
printf ( " Raspberry Pi 1 with BCM2708! \n " ) ;
fclose ( fd ) ;
return 1 ;
}
}
}
return 0 ;
}
//Physical addresses of peripheral depends on Raspberry Pi's version
void LinuxRCInput_Navio : : set_physical_addresses ( int version )
{
if ( version = = 1 ) {
dma_base = RCIN_NAVIO_RPI1_DMA_BASE ;
clk_base = RCIN_NAVIO_RPI1_CLK_BASE ;
pcm_base = RCIN_NAVIO_RPI1_PCM_BASE ;
}
else if ( version = = 2 ) {
dma_base = RCIN_NAVIO_RPI2_DMA_BASE ;
clk_base = RCIN_NAVIO_RPI2_CLK_BASE ;
pcm_base = RCIN_NAVIO_RPI2_PCM_BASE ;
}
}
//Map peripheral to virtual memory
void * LinuxRCInput_Navio : : map_peripheral ( uint32_t base , uint32_t len )
{
int fd = open ( " /dev/mem " , O_RDWR ) ;
void * vaddr ;
if ( fd < 0 ) {
printf ( " Failed to open /dev/mem: %m \n " ) ;
return NULL ;
}
vaddr = mmap ( NULL , len , PROT_READ | PROT_WRITE , MAP_SHARED , fd , base ) ;
if ( vaddr = = MAP_FAILED ) {
printf ( " rpio-pwm: Failed to map peripheral at 0x%08x: %m \n " , base ) ;
}
close ( fd ) ;
return vaddr ;
}
//Method to init DMA control block
void LinuxRCInput_Navio : : init_dma_cb ( dma_cb_t * * cbp , uint32_t mode , uint32_t source , uint32_t dest , uint32_t length , uint32_t stride , uint32_t next_cb )
{
( * cbp ) - > info = mode ;
( * cbp ) - > src = source ;
( * cbp ) - > dst = dest ;
( * cbp ) - > length = length ;
( * cbp ) - > next = next_cb ;
( * cbp ) - > stride = stride ;
}
//Non-stoping DMA when the process is finished will lead to crash
void LinuxRCInput_Navio : : stop_dma_and_exit ( int param )
{
dma_reg [ RCIN_NAVIO_DMA_CS | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = 0 ; // stop dma
exit ( 1 ) ;
}
//This function is used to init DMA control blocks (setting sampling GPIO register, destination adresses, synchronization)
void LinuxRCInput_Navio : : init_ctrl_data ( )
{
uint32_t phys_fifo_addr ;
uint32_t dest = 0 ;
uint32_t cbp = 0 ;
dma_cb_t * cbp_curr ;
//Set fifo addr (for delay)
phys_fifo_addr = ( ( pcm_base + 0x04 ) & 0x00FFFFFF ) | 0x7e000000 ;
2014-10-28 11:37:25 -03:00
2015-04-16 12:18:14 -03:00
//Init dma control blocks.
/*We are transferring 1 byte of GPIO register. Every 56th iteration we are
sampling TIMER register , which length is 8 bytes . So , for every 56 samples of GPIO we need
56 * 1 + 8 = 64 bytes of buffer . Value 56 was selected specially to have a 64 - byte " block "
TIMER - GPIO . So , we have integer count of such " blocks " at one virtual page . ( 4096 / 64 = 64
" blocks " per page . As minimum , we must have 2 virtual pages of buffer ( to have integer count of
vitual pages for control blocks ) : for every 56 iterations ( 64 bytes of buffer ) we need 56 control blocks for GPIO
sampling , 56 control blocks for setting frequency and 1 control block for sampling timer , so ,
we need 56 + 56 + 1 = 113 control blocks . For integer value , we need 113 pages of control blocks .
Each control block length is 32 bytes . In 113 pages we will have ( 113 * 4096 / 32 ) = 113 * 128 control
blocks . 113 * 128 control blocks = 64 * 128 bytes of buffer = 2 pages of buffer .
So , for 56 * 64 * 2 iteration we init DMA for sampling GPIO
and timer to ( 64 * 64 * 2 ) = 8192 bytes = 2 pages of buffer .
*/
// fprintf(stderr, "ERROR SEARCH1\n");
2015-07-01 09:04:57 -03:00
uint32_t i = 0 ;
for ( i = 0 ; i < 56 * 128 * RCIN_NAVIO_BUFFER_LENGTH ; i + + ) // 8 * 56 * 128 == 57344
2015-04-16 12:18:14 -03:00
{
2015-07-01 09:04:57 -03:00
//Transfer timer every 56th sample
if ( i % 56 = = 0 ) {
cbp_curr = ( dma_cb_t * ) con_blocks - > get_page ( con_blocks - > _virt_pages , cbp ) ;
2015-04-16 12:18:14 -03:00
2015-07-01 09:04:57 -03:00
init_dma_cb ( & cbp_curr , RCIN_NAVIO_DMA_NO_WIDE_BURSTS | RCIN_NAVIO_DMA_WAIT_RESP | RCIN_NAVIO_DMA_DEST_INC | RCIN_NAVIO_DMA_SRC_INC , RCIN_NAVIO_TIMER_BASE , ( uint32_t ) circle_buffer - > get_page ( circle_buffer - > _phys_pages , dest ) , 8 , 0 , ( uint32_t ) con_blocks - > get_page ( con_blocks - > _phys_pages , cbp + sizeof ( dma_cb_t ) ) ) ;
dest + = 8 ;
cbp + = sizeof ( dma_cb_t ) ;
}
2015-04-16 12:18:14 -03:00
// Transfer GPIO (1 byte)
2015-07-01 09:04:57 -03:00
cbp_curr = ( dma_cb_t * ) con_blocks - > get_page ( con_blocks - > _virt_pages , cbp ) ;
init_dma_cb ( & cbp_curr , RCIN_NAVIO_DMA_NO_WIDE_BURSTS | RCIN_NAVIO_DMA_WAIT_RESP , RCIN_NAVIO_GPIO_LEV0_ADDR , ( uint32_t ) circle_buffer - > get_page ( circle_buffer - > _phys_pages , dest ) , 1 , 0 , ( uint32_t ) con_blocks - > get_page ( con_blocks - > _phys_pages , cbp + sizeof ( dma_cb_t ) ) ) ;
2015-04-16 12:18:14 -03:00
dest + = 1 ;
cbp + = sizeof ( dma_cb_t ) ;
// Delay (for setting sampling frequency)
/* DMA is waiting data request signal (DREQ) from PCM. PCM is set for 1 MhZ freqency, so,
each sample of GPIO is limited by writing to PCA queue .
*/
2015-07-01 09:04:57 -03:00
cbp_curr = ( dma_cb_t * ) con_blocks - > get_page ( con_blocks - > _virt_pages , cbp ) ;
init_dma_cb ( & cbp_curr , RCIN_NAVIO_DMA_NO_WIDE_BURSTS | RCIN_NAVIO_DMA_WAIT_RESP | RCIN_NAVIO_DMA_D_DREQ | RCIN_NAVIO_DMA_PER_MAP ( 2 ) , RCIN_NAVIO_TIMER_BASE , phys_fifo_addr , 4 , 0 , ( uint32_t ) con_blocks - > get_page ( con_blocks - > _phys_pages , cbp + sizeof ( dma_cb_t ) ) ) ;
2015-04-16 12:18:14 -03:00
cbp + = sizeof ( dma_cb_t ) ;
}
//Make last control block point to the first (to make circle)
cbp - = sizeof ( dma_cb_t ) ;
2015-07-01 09:04:57 -03:00
( ( dma_cb_t * ) con_blocks - > get_page ( con_blocks - > _virt_pages , cbp ) ) - > next = ( uint32_t ) con_blocks - > get_page ( con_blocks - > _phys_pages , 0 ) ;
2015-04-16 12:18:14 -03:00
}
/*Initialise PCM
See BCM2835 documentation :
http : //www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*/
void LinuxRCInput_Navio : : init_PCM ( )
{
pcm_reg [ RCIN_NAVIO_PCM_CS_A ] = 1 ; // Disable Rx+Tx, Enable PCM block
hal . scheduler - > delay_microseconds ( 100 ) ;
clk_reg [ RCIN_NAVIO_PCMCLK_CNTL ] = 0x5A000006 ; // Source=PLLD (500MHz)
hal . scheduler - > delay_microseconds ( 100 ) ;
clk_reg [ RCIN_NAVIO_PCMCLK_DIV ] = 0x5A000000 | ( ( 50000 / RCIN_NAVIO_SAMPLE_FREQ ) < < 12 ) ; // Set pcm div. If we need to configure DMA frequency.
hal . scheduler - > delay_microseconds ( 100 ) ;
clk_reg [ RCIN_NAVIO_PCMCLK_CNTL ] = 0x5A000016 ; // Source=PLLD and enable
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_TXC_A ] = 0 < < 31 | 1 < < 30 | 0 < < 20 | 0 < < 16 ; // 1 channel, 8 bits
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_MODE_A ] = ( 10 - 1 ) < < 10 ; //PCM mode
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_CS_A ] | = 1 < < 4 | 1 < < 3 ; // Clear FIFOs
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_DREQ_A ] = 64 < < 24 | 64 < < 8 ; // DMA Req when one slot is free?
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_CS_A ] | = 1 < < 9 ; // Enable DMA
hal . scheduler - > delay_microseconds ( 100 ) ;
pcm_reg [ RCIN_NAVIO_PCM_CS_A ] | = 1 < < 2 ; // Enable Tx
hal . scheduler - > delay_microseconds ( 100 ) ;
}
/*Initialise DMA
See BCM2835 documentation :
http : //www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*/
void LinuxRCInput_Navio : : init_DMA ( )
{
dma_reg [ RCIN_NAVIO_DMA_CS | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = RCIN_NAVIO_DMA_RESET ; //Reset DMA
hal . scheduler - > delay_microseconds ( 100 ) ;
dma_reg [ RCIN_NAVIO_DMA_CS | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = RCIN_NAVIO_DMA_INT | RCIN_NAVIO_DMA_END ;
2015-07-01 09:04:57 -03:00
dma_reg [ RCIN_NAVIO_DMA_CONBLK_AD | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = reinterpret_cast < uint32_t > ( con_blocks - > get_page ( con_blocks - > _phys_pages , 0 ) ) ; //Set first control block address
2015-04-16 12:18:14 -03:00
dma_reg [ RCIN_NAVIO_DMA_DEBUG | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = 7 ; // clear debug error flags
dma_reg [ RCIN_NAVIO_DMA_CS | RCIN_NAVIO_DMA_CHANNEL < < 8 ] = 0x10880001 ; // go, mid priority, wait for outstanding writes
}
//We must stop DMA when the process is killed
void LinuxRCInput_Navio : : set_sigaction ( )
{
for ( int i = 0 ; i < 64 ; i + + ) {
//catch all signals (like ctrl+c, ctrl+z, ...) to ensure DMA is disabled
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = LinuxRCInput_Navio : : stop_dma_and_exit ;
sigaction ( i , & sa , NULL ) ;
}
}
//Initial setup of variables
LinuxRCInput_Navio : : LinuxRCInput_Navio ( ) :
prev_tick ( 0 ) ,
delta_time ( 0 ) ,
curr_tick_inc ( 1000 / RCIN_NAVIO_SAMPLE_FREQ ) ,
curr_pointer ( 0 ) ,
curr_channel ( 0 ) ,
width_s0 ( 0 ) ,
curr_signal ( 0 ) ,
last_signal ( 228 ) ,
state ( RCIN_NAVIO_INITIAL_STATE )
{
int version = get_raspberry_pi_version ( ) ;
set_physical_addresses ( version ) ;
//Init memory for buffer and for DMA control blocks. See comments in "init_ctrl_data()" to understand values "2" and "113"
circle_buffer = new Memory_table ( RCIN_NAVIO_BUFFER_LENGTH * 2 , version ) ;
con_blocks = new Memory_table ( RCIN_NAVIO_BUFFER_LENGTH * 113 , version ) ;
}
LinuxRCInput_Navio : : ~ LinuxRCInput_Navio ( )
{
delete circle_buffer ;
delete con_blocks ;
}
//Initializing necessary registers
void LinuxRCInput_Navio : : init_registers ( )
{
dma_reg = ( uint32_t * ) map_peripheral ( dma_base , RCIN_NAVIO_DMA_LEN ) ;
pcm_reg = ( uint32_t * ) map_peripheral ( pcm_base , RCIN_NAVIO_PCM_LEN ) ;
clk_reg = ( uint32_t * ) map_peripheral ( clk_base , RCIN_NAVIO_CLK_LEN ) ;
}
void LinuxRCInput_Navio : : init ( void * )
{
2014-10-28 11:37:25 -03:00
2015-04-16 12:18:14 -03:00
init_registers ( ) ;
2014-10-28 11:37:25 -03:00
2015-04-16 12:18:14 -03:00
//Enable PPM input
enable_pin = hal . gpio - > channel ( PPM_INPUT_NAVIO ) ;
enable_pin - > mode ( HAL_GPIO_INPUT ) ;
//Configuration
set_sigaction ( ) ;
init_ctrl_data ( ) ;
init_PCM ( ) ;
init_DMA ( ) ;
//wait a bit to let DMA fill queues and come to stable sampling
hal . scheduler - > delay ( 300 ) ;
//Reading first sample
2015-07-01 09:04:57 -03:00
curr_tick = * ( ( uint64_t * ) circle_buffer - > get_page ( circle_buffer - > _virt_pages , curr_pointer ) ) ;
2015-04-16 12:18:14 -03:00
prev_tick = curr_tick ;
curr_pointer + = 8 ;
2015-07-01 09:04:57 -03:00
curr_signal = * ( ( uint8_t * ) circle_buffer - > get_page ( circle_buffer - > _virt_pages , curr_pointer ) ) & 0x10 ? 1 : 0 ;
2015-04-16 12:18:14 -03:00
last_signal = curr_signal ;
curr_pointer + + ;
2014-10-26 16:18:04 -03:00
}
2015-04-16 12:18:14 -03:00
//Processing signal
2014-10-26 16:18:04 -03:00
void LinuxRCInput_Navio : : _timer_tick ( )
{
2015-04-16 12:18:14 -03:00
int j ;
void * x ;
//Now we are getting address in which DMAC is writing at current moment
2015-07-01 09:04:57 -03:00
dma_cb_t * ad = ( dma_cb_t * ) con_blocks - > get_virt_addr ( dma_reg [ RCIN_NAVIO_DMA_CONBLK_AD | RCIN_NAVIO_DMA_CHANNEL < < 8 ] ) ;
2015-04-16 12:18:14 -03:00
for ( j = 1 ; j > = - 1 ; j - - ) {
2015-07-01 09:04:57 -03:00
x = circle_buffer - > get_virt_addr ( ( ad + j ) - > dst ) ;
if ( x ! = NULL ) {
break ; }
2015-04-16 12:18:14 -03:00
}
//How many bytes have DMA transfered (and we can process)?
2015-07-01 09:04:57 -03:00
counter = circle_buffer - > bytes_available ( curr_pointer , circle_buffer - > get_offset ( circle_buffer - > _virt_pages , ( uint32_t ) x ) ) ;
2015-04-16 12:18:14 -03:00
//We can't stay in method for a long time, because it may lead to delays
if ( counter > RCIN_NAVIO_MAX_COUNTER ) {
counter = RCIN_NAVIO_MAX_COUNTER ;
}
//Processing ready bytes
for ( ; counter > 0x40 ; counter - - ) {
//Is it timer samle?
if ( curr_pointer % ( 64 ) = = 0 ) {
2015-07-01 09:04:57 -03:00
curr_tick = * ( ( uint64_t * ) circle_buffer - > get_page ( circle_buffer - > _virt_pages , curr_pointer ) ) ;
2015-04-16 12:18:14 -03:00
curr_pointer + = 8 ;
counter - = 8 ;
2014-10-28 11:37:25 -03:00
}
2015-04-16 12:18:14 -03:00
//Reading required bit
2015-07-01 09:04:57 -03:00
curr_signal = * ( ( uint8_t * ) circle_buffer - > get_page ( circle_buffer - > _virt_pages , curr_pointer ) ) & 0x10 ? 1 : 0 ;
2015-04-16 12:18:14 -03:00
//If the signal changed
if ( curr_signal ! = last_signal ) {
delta_time = curr_tick - prev_tick ;
prev_tick = curr_tick ;
switch ( state ) {
case RCIN_NAVIO_INITIAL_STATE :
state = RCIN_NAVIO_ZERO_STATE ;
break ;
case RCIN_NAVIO_ZERO_STATE :
if ( curr_signal = = 0 ) {
width_s0 = ( uint16_t ) delta_time ;
state = RCIN_NAVIO_ONE_STATE ;
break ;
}
else
break ;
case RCIN_NAVIO_ONE_STATE :
if ( curr_signal = = 1 ) {
width_s1 = ( uint16_t ) delta_time ;
state = RCIN_NAVIO_ZERO_STATE ;
_process_rc_pulse ( width_s0 , width_s1 ) ;
break ;
}
else
break ;
}
}
last_signal = curr_signal ;
curr_pointer + + ;
if ( curr_pointer > = circle_buffer - > get_page_count ( ) * PAGE_SIZE ) {
curr_pointer = 0 ;
}
curr_tick + = curr_tick_inc ;
}
2014-10-26 16:18:04 -03:00
}
# endif // CONFIG_HAL_BOARD_SUBTYPE