📄 bfsi.c
字号:
if (isr_between_diff > 800000) { isr_between_skip++; isr_between_difflastskip = isr_between_diff; } /* read and write sample callbacks */ read_samples = isr_read_processing(); write_samples = isr_write_processing(); if ((bfsi_isr_callback != NULL) && !bfsi_freeze) { bfsi_isr_callback(read_samples, write_samples); } __builtin_bfin_ssync(); /* some stats to help monitor the cycles used by ISR processing */ /* Simple IIR averager: y(n) = (1 - 1/TC)*y(n) + (1/TC)*x(n) After conversion to fixed point: 2*y(n) = ((TC-1)*2*y(n) + 2*x(n) + half_lsb ) >> LTC */ isr_cycles_average = ( (u32)(TC-1)*isr_cycles_average + (((u32)isr_cycles_last)<<1) + TC) >> LTC; if (isr_cycles_last > isr_cycles_worst) isr_cycles_worst = isr_cycles_last; /* we sample right at the end to make sure we count cycles used to measure cycles! */ isr_cycles_last = cycles() - start_cycles; return IRQ_HANDLED;}static int init_sport_interrupts(void){ //unsigned int data32; #if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) if(request_irq(IRQ_SPORT0_RX, sport_rx_isr, SA_INTERRUPT, "sport rx", NULL) != 0) { return -EBUSY; }#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) if(request_irq(IRQ_SPORT0_RX, sport_rx_isr, SA_INTERRUPT, "sport rx", NULL) != 0) { return -EBUSY; }#endif#if defined(BFSI_SPORT1) if(request_irq(IRQ_SPORT1_RX, sport_rx_isr, SA_INTERRUPT, "sport rx", NULL) != 0) { return -EBUSY; }#endif#endif if (bfsi_debug) { printk("ISR installed OK\n"); }#if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) /* enable DMA1 sport0 Rx interrupt */ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 0x00000200); __builtin_bfin_ssync();#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) /* enable DMA3 sport0 Rx interrupt */ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 0x00000020); __builtin_bfin_ssync();#endif#if defined(BFSI_SPORT1) /* enable DMA5 sport1 Rx interrupt */ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 0x00000080); __builtin_bfin_ssync();#endif#endif return 0;}static void enable_dma_sport(void){ /* enable DMAs */#if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) bfin_write_DMA2_CONFIG(bfin_read_DMA2_CONFIG() | DMAEN); bfin_write_DMA1_CONFIG(bfin_read_DMA1_CONFIG() | DMAEN); __builtin_bfin_ssync(); /* enable sport0 Tx and Rx */ bfin_write_SPORT0_TCR1(bfin_read_SPORT0_TCR1() | TSPEN); bfin_write_SPORT0_RCR1(bfin_read_SPORT0_RCR1() | RSPEN); __builtin_bfin_ssync();#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) bfin_write_DMA4_CONFIG(bfin_read_DMA4_CONFIG() | DMAEN); bfin_write_DMA3_CONFIG(bfin_read_DMA3_CONFIG() | DMAEN); __builtin_bfin_ssync(); /* enable sport0 Tx and Rx */ bfin_write_SPORT0_TCR1(bfin_read_SPORT0_TCR1() | TSPEN); bfin_write_SPORT0_RCR1(bfin_read_SPORT0_RCR1() | RSPEN); __builtin_bfin_ssync();#endif#if defined(BFSI_SPORT1) bfin_write_DMA6_CONFIG(bfin_read_DMA6_CONFIG() | DMAEN); bfin_write_DMA5_CONFIG(bfin_read_DMA5_CONFIG() | DMAEN); __builtin_bfin_ssync(); /* enable sport1 Tx and Rx */ bfin_write_SPORT1_TCR1(bfin_read_SPORT1_TCR1() | TSPEN); bfin_write_SPORT1_RCR1(bfin_read_SPORT1_RCR1() | RSPEN); __builtin_bfin_ssync();#endif#endif}static void disable_sport(void){#if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) /* disable sport0 Tx and Rx */ bfin_write_SPORT0_TCR1(bfin_read_SPORT0_TCR1() & (~TSPEN)); bfin_write_SPORT0_RCR1(bfin_read_SPORT0_RCR1() & (~RSPEN)); __builtin_bfin_ssync(); /* disable DMA1 and DMA2 */ bfin_write_DMA2_CONFIG(bfin_read_DMA2_CONFIG() & (~DMAEN)); bfin_write_DMA1_CONFIG(bfin_read_DMA1_CONFIG() & (~DMAEN)); __builtin_bfin_ssync(); bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & (~0x00000200)); __builtin_bfin_ssync();#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) /* disable sport0 Tx and Rx */ bfin_write_SPORT0_TCR1(bfin_read_SPORT0_TCR1() & (~TSPEN)); bfin_write_SPORT0_RCR1(bfin_read_SPORT0_RCR1() & (~RSPEN)); __builtin_bfin_ssync(); /* disable DMA3 and DMA4 */ bfin_write_DMA4_CONFIG(bfin_read_DMA4_CONFIG() & (~DMAEN)); bfin_write_DMA3_CONFIG(bfin_read_DMA3_CONFIG() & (~DMAEN)); __builtin_bfin_ssync(); bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & (~0x00000020)); __builtin_bfin_ssync();#endif#if defined(BFSI_SPORT1) /* disable sport1 Tx and Rx */ bfin_write_SPORT1_TCR1(bfin_read_SPORT1_TCR1() & (~TSPEN)); bfin_write_SPORT1_RCR1(bfin_read_SPORT1_RCR1() & (~RSPEN)); __builtin_bfin_ssync(); /* disable DMA3 and DMA4 */ bfin_write_DMA6_CONFIG(bfin_read_DMA6_CONFIG() & (~DMAEN)); bfin_write_DMA5_CONFIG(bfin_read_DMA5_CONFIG() & (~DMAEN)); __builtin_bfin_ssync(); bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & (~0x00000080)); __builtin_bfin_ssync();#endif#endif}int bfsi_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len; len = sprintf(buf, "readchunk_first.........: %d\n" "readchunk_second........: %d\n" "readchunk_didntswap.....: %d\n" "bad_x...................: %d %d %d %d %d\n" "log_readchunk...........: 0x%08x\n" "writechunk_first........: %d\n" "writechunk_second.......: %d\n" "writechunk_didntswap....: %d\n" "isr_cycles_last.........: %d\n" "isr_cycles_worst........: %d\n" "isr_cycles_average......: %d\n" "echo_sams...............: %d\n" "isr_between_diff........: %d\n" "isr_between_worst.......: %d\n" "isr_between_skip........: %d\n" "isr_between_difflastskip: %d\n", readchunk_first, readchunk_second, readchunk_didntswap, bad_x[0],bad_x[1],bad_x[2],bad_x[3],bad_x[4], log_readchunk, writechunk_first, writechunk_second, writechunk_didntswap, isr_cycles_last, isr_cycles_worst, isr_cycles_average>>1, echo_sams, isr_between_diff, isr_between_worst, isr_between_skip, isr_between_difflastskip); *eof=1; return len;}static int proc_read_bfsi_freeze(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len; unsigned int flags; *eof = 1; len = sprintf(buf, "%d\n", bfsi_freeze); return len;}static int proc_write_bfsi_freeze(struct file *file, const char *buffer, unsigned long count, void *data){ int new_freeze; char *endbuffer; unsigned int flags; new_freeze = simple_strtol (buffer, &endbuffer, 10); bfsi_freeze = new_freeze; return count;}static int proc_write_bfsi_reset(struct file *file, const char *buffer, unsigned long count, void *data){ int i; isr_cycles_worst = 0; isr_between_worst = 0; isr_between_skip = 0; isr_between_difflastskip = 0; readchunk_first = 0; readchunk_second = 0; readchunk_didntswap = 0; writechunk_first = 0; writechunk_second = 0; writechunk_didntswap = 0; for(i=0; i<5; i++) bad_x[i] = 0; return count;}/* Wrapper for entire SPORT setup, returns 1 for success, 0 for failure. The SPORT code is designed to deliver small arrays of size samples every (125us * samples). A ping-pong arrangement is used, so the address of the buffer will alternate every call between two possible values. The callback functions privide to the address of the current buffer for the read and write channels. Read means the data was just read from the SPORT, so this is the "receive" PCM samples. Write is the PCM data to be written to the SPORT. The callbacks are called in the context of an interrupt service routine, so treat any code them like an ISR. Once this function returns successfully the SPORT/DMA will be up and running, and calls to the isr callback will start. For testing it is OK to set the callback function pointer to NULL, say if you just want to look at the debug information. If debug==1 then "cat /proc/bfsi" will display some debug information, something like: readchunk_first.....: 9264 readchunk_second....: 9264 readchunk_didntswap.: 0 writechunk_first....: 9264 writechunk_second...: 9264 writechunk_didntswap: 0 If all is well then "readchunk_didntswap" and "writechunk_didntswap" will be static and some very small number. The first and second values should be at most one value different. These variables indicate sucessful ping-pong operation. The numbers are incremented ever interrupt, for example if samples=8 (typical for zaptel), then we get one interrupt every ms, or 1000 interrupts per second. This means the values for each first/second entry should go up 500 times per second. 8 channels are sampled at once, so the size of the samples buffers is 8*samples (typically 64 bytes for zaptel). TODO: 1/ It might be nice to modify this function allow user defined SPORT control reg settings, for example to change clock dividers and frame sync sources. Or posible provide a bfsi_sport_set() function. 2/ Modify the callbacks to provide user-dfine context information. 3/ Modify init to define max number of channels, it is currently hard coded at 8.*/int bfsi_sport_init( void (*isr_callback)(u8 *read_samples, u8 *write_samples), int samples, int debug){ struct proc_dir_entry *freeze, *reset; if (debug) { create_proc_read_entry("bfsi", 0, NULL, bfsi_proc_read, NULL); bfsi_debug = debug; freeze = create_proc_read_entry("bfsi_freeze", 0, NULL, proc_read_bfsi_freeze, NULL); freeze->write_proc = proc_write_bfsi_freeze; reset = create_proc_read_entry("bfsi_reset", 0, NULL, NULL, NULL); reset->write_proc = proc_write_bfsi_reset; } bfsi_isr_callback = isr_callback; samples_per_chunk = samples;#if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) init_sport0();#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) init_sport0();#endif#if defined(BFSI_SPORT1) init_sport1();#endif#endif init_dma_wc(); enable_dma_sport(); if (init_sport_interrupts()) init_ok = 0; else init_ok = 1; return init_ok;}/* shut down SPORT operation cleanly */void bfsi_sport_close(void){ disable_sport(); if (init_ok) {#if (defined(CONFIG_BF533) || defined(CONFIG_BF532)) free_irq(IRQ_SPORT0_RX, NULL);#endif#if defined(CONFIG_BF537)#if defined(BFSI_SPORT0) free_irq(IRQ_SPORT0_RX, NULL);#endif#if defined(BFSI_SPORT1) free_irq(IRQ_SPORT1_RX, NULL);#endif#endif }#if L1_DATA_A_LENGTH != 0 l1_data_A_sram_free(iTxBuffer1); l1_data_A_sram_free(iRxBuffer1);#else dma_free_coherent(NULL, 2*samples_per_chunk*8, iTxBuffer1, 0); dma_free_coherent(NULL, 2*samples_per_chunk*8, iRxBuffer1, 0);#endif remove_proc_entry("bfsi", NULL); remove_proc_entry("bfsi_freeze", NULL); remove_proc_entry("bfsi_reset", NULL);}MODULE_LICENSE("GPL");EXPORT_SYMBOL(bfsi_spi_write_8_bits);EXPORT_SYMBOL(bfsi_spi_read_8_bits);EXPORT_SYMBOL(bfsi_spi_init);EXPORT_SYMBOL(bfsi_sport_init);EXPORT_SYMBOL(bfsi_reset);EXPORT_SYMBOL(bfsi_sport_close);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -