/****************************************************************************** 版权所有: 文件名称: adc.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2025-06-09 功能说明: adc驱动程序。 其它说明: 修改记录: */ /*------------------------------ 头文件 --------------------------------------- */ #include "bsp.h" #include "rt.h" #include "head.h" #include #include "rt_printf.h" // #include "shm_comm_packet.h" #include #include "shmem.h" /*------------------------------ 宏定义 --------------------------------------- */ #if CFG_BSP_DEBUG #define _ADC_DEBUG #endif #define AC_HZ_NORMAL 50.0 // 交流标准频率 #define ADC_DOT_BUF_SIZE ((CFG_ADC_CHANNEL)*(CFG_ADC_DOTS_PER_CHANNEL*2)*2) /*------------------------------ 全局变量 ------------------------------------- */ // AD片选地址,8、9、10、11槽对应CS2、CS1、CS3、CS4。 static int g_adc_slot2cs[EQU_SLOT_AC_NUM] = {0}; static u8 g_adc_chip; static u32 g_adc_range[EQU_SLOT_AC_NUM]; const u8 g_cs_channel_table[CFG_ADC_CHANNEL]={1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16}; //每个通道占用的空间:CFG_ADC_DOTS_PER_CHANNEL*2*2 = 128*2*2=512 //通道数:CFG_ADC_CHANNEL+2= 64+2=66 //总空间:512*18=9216=0x2400 //保证首地址是buf长度两倍的倍数。以利用MAC计算的MASK寄存器来达到 //循环buf的功能。注意每个通道buf的后半部分目前没有利用,以后可以用来干需要干的事情. //通道加2,用作开入开出等状态保存。 // 不能使用分配的DMA内存,因为冷火实时linux平台不能使用动态内存映射。 //short (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2]; //s16 (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2] = (short (*)[CFG_ADC_DOTS_PER_CHANNEL*2])0x8ff00000; s16 (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2]; struct timespec ts_adc_dots[CFG_ADC_DOTS_PER_CHANNEL];//时间戳 // 128点录波,32点计算 // 注意此buf由于是DMA类型,不能在实时中断中使用,只能在线程中使用。 //s16 g_adc_dots_rec[CFG_ADC_DOTS_PER_CHANNEL*4][CFG_ADC_CHANNEL]; s16 (*g_adc_dots_rec)[CFG_ADC_CHANNEL]; u32 g_adc_dots_rec_dma; // 直流量测量采样点BUF u16 g_adc_dots_dc[CFG_ADC_CHANNEL_DC][CFG_ADC_DOTS_PER_CHANNEL]; //ADC同步标志,表示ADC采样点BUFFER中的数据是否有效,AD7616转换的第一次数据也无效。 int g_adc_sync = -(CFG_ADC_DOTS_PER_CHANNEL+1); // ADC点BUF的索引,当前索引下无值。 volatile unsigned long g_adc_dots_count; int g_adc_channel; unsigned long g_adZero=14790; char g_adc_name[CFG_ADC_CHANNEL_ALL][20]; struct rt_stat g_stat_adc[CFG_ADC_CHANNEL_ALL]; // 跟踪频率 float g_freq = 50.0 ; // 直流量测量采样点BUF u16 g_adc_dots_dc[CFG_ADC_CHANNEL_DC][CFG_ADC_DOTS_PER_CHANNEL]; uint32_t g_yx_buf[2] = {0xffffffff,0xffffffff}; //预留64个遥信 int g_adc_stat_flag=0; volatile unsigned int adc_wp; volatile unsigned int adc_rp; bool prt_flag; volatile unsigned long g_adc_dots_data_count; SHM_VER_T LuoHe_version; /*------------------------------ 函数声明 ------------------------------------- */ void dido_di_poll(SHM_SAMPLE_T *sample_data); /*------------------------------ 外部函数 ------------------------------------- */ //设置各通道的参考电压 static int write_v_default(uint8_t no, uint8_t *data) { int ret = 0; int cnt = 0; if(data == NULL) return -1; while(1) { // ret = shm_comm_packet_write(SHM_ADDR_D_RFV_1+(SHM_ADDR_D_RFV_2-SHM_ADDR_D_RFV_1)*no, data, sizeof(SHM_RFV_T)); if(ret > 0) { break; } if(++cnt > 3) break; usleep(30); } return ret; } int adc_set_v_default(int no, u32 value) { int ret = 0; SHM_RFV_T v; v.rc = value; ret = write_v_default(no,(uint8_t *)&v); return ret; } void adc_get_range_config(int no,int slot) { int i,scale,channel,shift; u32 rc; rc = 0; for(i=0;i 0) { return wp.write_flag_A; } if(++cnt > 3) break; usleep(30); } return ret; } static int get_adc_sample(uint32_t addr, int index, uint8_t *out_data) { SHM_SAMPLE_T sample; int ret = 0; int cnt = 0; if(out_data == NULL) return -1; while(1) { ret = shm_comm_packet_read_noABcrc(addr + index*(sizeof(sample)), sizeof(sample), out_data, sizeof(sample)); if(ret > 0) { break; } if(++cnt > 3) break; usleep(30); } return ret; } static int get_e907_version(SHM_VER_T* par) { SHM_VER_T ver; int ret = 0; int cnt = 0; if(par == NULL) return -1; while(1) { ret = shm_comm_packet_read(SHM_ADDR_U_VER, sizeof(ver), (uint8_t *)&ver, sizeof(ver)); if(ret > 0) { par->ver = ver.ver; par->v_crc = ver.v_crc; strcpy(par->time,ver.time); return 0; } if(++cnt > 3) break; usleep(30); } return -1; } int adc_init(void) { int ret = 0; int i; /* ret = get_adc_wp(); if(ret < 0) { rt_printf("get_adc_wp 返回错误值,ret=%d!\r\n",adc_wp); return -1; } adc_wp = adc_rp = ret; */ memset(&LuoHe_version,0,sizeof(LuoHe_version)); g_adc_dots_count=0; prt_flag=false; // 采样计算点BUF初始化 // 32;周波数 g_adc_dots = malloc(ADC_DOT_BUF_SIZE); if(g_adc_dots == NULL) { rt_printf("g_adc_dots 分配失败!\r\n"); return -1; } memset(g_adc_dots, 0x55, ADC_DOT_BUF_SIZE); g_adc_dots_data_count=0; // 录波点BUF初始化 // 32;周波数 g_adc_dots_rec = malloc(CFG_ADC_CHANNEL*2*ADC_REC_DOTS_CHANNEL); if(g_adc_dots_rec == NULL) { rt_printf("g_adc_dots_rec 分配失败!\r\n"); rt_free(g_adc_dots); g_adc_dots = NULL; return -1; } // 初始化统计变量 for(i=0; i=SHM_ADC_WR_NUM) { adc_wp=0; } if(adc_rp>=SHM_ADC_WR_NUM) { adc_rp=0; } while(adc_wp!=adc_rp) { opt=((g_adc_dots_data_count&(ADC_REC_SAMPLE_RATE-1))==0)?TRUE:FALSE; ret = get_adc_sample(SHM_ADDR_U_ADC_1, adc_rp,(uint8_t *)&sample_data[0]); ret = get_adc_sample(SHM_ADDR_U_ADC_2, adc_rp,(uint8_t *)&sample_data[1]); if(ret < 0) { if(++cnt > 3) { rt_printf("get_adc_sample 返回错误值, ret=%d!\r\n",ret); break; } continue; } //保存yx值 g_yx_buf[0] = sample_data[0].yx_buf[0]; g_yx_buf[1] = sample_data[1].yx_buf[1]; if(!recv_init) { recv_init = 1; //开机时裸核还没有把遥信送上下,这里重新初始化plc_init // plc_init(); TODO EWen } // 标准化DTU遥信已经经过开入子板处理防抖 // dido_di_poll(&sample_data[0]); for(i=0; i<16; i++) { g_adc_dots_rec[g_adc_dots_index_rec][i] = sample_data[0].sample_buf[i]; if(opt==TRUE) { g_adc_dots[i][g_adc_dots_index] = sample_data[0].sample_buf[i]; ts_adc_dots[g_adc_dots_index] = sample_data[0].ts; } } for(i=16; i=SHM_ADC_WR_NUM) adc_rp=0; } return 0; } static void updata_adc(struct t_shmdata_adc *sample_data0, uint16_t us_adc_dot_index0) { int i = 0; int index = 0; static int mod = 0; int opt = ((g_adc_dots_data_count & (ADC_REC_SAMPLE_RATE - 1)) == 0) ? TRUE : FALSE; // uint32_t ul_adc_idx_1 = 0, ul_adc_idx_2 = 0; // 每片16路 for (uint8_t j = 0; j < CFG_ADC_CHANNEL; j++) { if (AD7616_DC0_CHANNEL == j) { g_adc_dots_dc[0][g_adc_dots_data_count & CFG_ADC_DOTS_MASK] = sample_data0->data.usa_sample_dots[AD7616_DC0_CHANNEL][us_adc_dot_index0]; } else if(AD7616_DC1_CHANNEL == j) { g_adc_dots_dc[1][g_adc_dots_data_count & CFG_ADC_DOTS_MASK] = sample_data0->data.usa_sample_dots[AD7616_DC0_CHANNEL][us_adc_dot_index0]; } else { g_adc_dots_rec[g_adc_dots_index_rec][j] = sample_data0->data.usa_sample_dots[j][us_adc_dot_index0]; // ul_adc_idx_1 = g_adc_dots_index_rec; if (opt == TRUE) { g_adc_dots[j][g_adc_dots_index] = sample_data0->data.usa_sample_dots[j][us_adc_dot_index0]; // ul_adc_idx_2 = g_adc_dots_index; } } } if (opt == TRUE) { index = g_adc_dots_index; // 统计数据 if (g_adc_stat_flag) { for (i = 0; i < CFG_ADC_CHANNEL; i++) { rt_stat_in(&g_stat_adc[i], (unsigned short)(g_adc_dots[i][index] + 32768)); } } // 通道取反 for (i = 0; i < g_equ_adc_inv_num; i++) { g_adc_dots[g_equ_adc_inv[i]][index] = -(g_adc_dots[g_equ_adc_inv[i]][index]); } // 全部BUFFER都是新数据,才能算同步好。 if (g_adc_sync < 1) { g_adc_sync++; } // 索引值加一 g_adc_dots_count++; // 保护计数+突变量 { dTCounter++; if (dTCounter % 8 == 0) { prt_flag = true; } // 突变量 if (g_adc_sync == 1 && g_sw_init == 1) { protect_tbl_qd(); } } } #ifdef XDL_ZT xdl_tbl_qd(mod); #endif mod++; mod &=(CFG_ADC_MOD_NUM-1); g_adc_dots_data_count++; } /** * @brief 新方式获取共享内存数据 * * @param mod * @return int * @author zhl */ int adc_isr_new(int mod) { int ret0 = 0; struct t_shmdata_adc sample_data0 = {0}; static volatile uint16_t smus_sample_read_index0 = 0; /* 读取adc1索引 */ ret0 = shm_packet_read_v2(SHM_ADDR_W_U_ADC_1, sizeof(sample_data0), (uint8_t *)&sample_data0, sizeof(sample_data0)); // printf("ret0=%d, sample_idx=%d, read_index=%d, us_updata=%d, us_op=%d, us_op_bk=%d\n", // ret0, sample_data0.data.us_sample_idx, smus_sample_read_index0, sample_data0.us_updata, sample_data0.us_op, sample_data0.us_op_bk); if (0 > ret0) { return -1; } if (ret0 > 0 && (smus_sample_read_index0 != sample_data0.data.us_sample_idx)) { uint16_t us_adc_dot_num0 = 0; if (sample_data0.data.us_sample_idx > smus_sample_read_index0) { us_adc_dot_num0 = sample_data0.data.us_sample_idx - smus_sample_read_index0; } else { us_adc_dot_num0 = (sample_data0.data.us_sample_idx + TC_ADC_DOTS_PER_CHANNEL) - smus_sample_read_index0; } // printf("us_adc_dot_num0:%d\n", us_adc_dot_num0); // us_adc_dot_num0 与 us_adc_dot_num1的数量一般相同 for (uint16_t i = 0; i < us_adc_dot_num0; i++) { /* 注意采样下标索引不能超过采样缓存 TC_ADC_DOTS_PER_CHANNEL */ uint16_t us_adc_dot_index0 = (smus_sample_read_index0 + i) % TC_ADC_DOTS_PER_CHANNEL; // test zhl // int32_t physical_value0 = (int16_t)(sample_data0.data.usa_sample_dots[9][us_adc_dot_index0]); // printf("%d, ", physical_value0); // int32_t physical_value1 = (int16_t)(sample_data1.data.usa_sample_dots[1][us_adc_dot_index1]); // printf("%d, ", physical_value1); updata_adc(&sample_data0, us_adc_dot_index0); } smus_sample_read_index0 = (smus_sample_read_index0 + us_adc_dot_num0) % TC_ADC_DOTS_PER_CHANNEL; } return 0; } /****************************************************************************** 函数名称: adc_slot_is_ok 函数版本: 01.01 创建作者: sunxi 创建日期: 2016-02-01 函数说明: 检查对应槽的ADC芯片是否安装或损坏。 参数说明: slot: 0~3;从g_ac_slot_begin开始 返回值: 成功返回0. 修改记录: */ int adc_slot_is_ok(int slot) { if((u32)slot >= EQU_SLOT_AC_NUM) { return 0; } if(g_adc_chip & (1<= CFG_ADC_DOTS_PER_PERIOD) { index = index - CFG_ADC_DOTS_PER_PERIOD; index &= (~0x1); p = (short *)&g_adc_dots[channel][index]; } else { index = CFG_ADC_DOTS_PER_CHANNEL-CFG_ADC_DOTS_PER_PERIOD+index; index &= (~0x1); for(i = 0;i < CFG_ADC_DOTS_PER_CHANNEL - index;i++) { sam_buf[channel][i] = g_adc_dots[channel][index+i]; } for(i = 0;i cnt) { avg = stat->sum/stat->cnt; } rt_printf("%-24s%ld\t%ld\t%ld\t%ld\t%-16ld%ld\r\n",stat->name,stat->min,stat->max,stat->max - stat->min,avg,stat->sum,stat->cnt); } return 0; } int adc_stat_reset(void) { int i; g_adc_stat_flag = 0; for(i=0; i 0) { break; } if(++cnt > 3) break; usleep(30); } return ret; } #endif float dc_get(unsigned int index) { u32 i, v; float f; if(index >= CFG_ADC_CHANNEL_DC) return 0.0; v = 0; for (i = 0; i < CFG_ADC_DOTS_PER_CHANNEL; i++) { v += (u16)g_adc_dots_dc[index][i]; } f = (float)v / CFG_ADC_DOTS_PER_CHANNEL; // 乘理论系数 f /= 129.791f; return f; } /*------------------------------ 测试函数 ------------------------------------- */ #ifdef _ADC_DEBUG int adc_test(void) { return 0; } #endif /*------------------------------ 文件结束 ------------------------------------- */