bool_t debug_dm9000a_write_reg(char *param) { char *word, *next_param; u32 reg = 0; u32 value = 0; // 提取为SOCKET号 if (param) { next_param = param; word = Sh_GetWord(next_param, &next_param); reg = __sh_atol(word); word = Sh_GetWord(next_param, &next_param); value = __sh_atol(word); word = Sh_GetWord(next_param, &next_param); if(word != NULL) { printf("\r\n参数错误\r\n"); return false; } } if (Lock_SempPend(semp_dm9000, 10000*mS) == true) { Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 printf("\r\n写入DM9000A的【%4x】寄存器:%4x", reg, value); iow(reg, value); printf("\r\n"); Int_RestoreAsynLine(cn_int_line_enet); // 打开DM9000A的外部中断 Lock_SempPost(semp_dm9000); } return true; }
//----等待MultiplexSets----------------------------------------------------------- //功能: 设置好MultiplexSets后,应用程序调用本函数等待MultiplexSets被触发,根据 // Type值,等待方式分轮询和异步触发两种。 //参数: Sets,被操作的MultiplexSets指针 // Status,返回对象当前状态的指针,如果应用程序不关心其状态,可以给NULL。 // Timeout,阻塞等待的最长时间,uS。 //返回:如果MultiplexSets被触发,则返回MultiplexSets中一个被触发对象的ObjectID, // 否则返回-1. //----------------------------------------------------------------------------- ptu32_t Multiplex_Wait(struct tagMultiplexSetsCB *Sets, u32 *Status, u32 Timeout) { struct tagMultiplexObjectCB *Object; ptu32_t result; if (Sets == NULL) return -1; if ((Sets->ActiveQ == NULL) && (Sets->ObjectQ == NULL)) return -1; //判断或等待直到MultiplexSets被触发。 if (!__SetsIsActived(Sets)) { Lock_SempPend(&Sets->Lock, Timeout); } if (Sets->ActiveQ != NULL) { //阻塞等待结束后,SetsActived非空即视为触发。 Sets->SetsActived = true; Object = Sets->ActiveQ; result = Object->ObjectID; if (Status != NULL) *Status = Object->PendingBit; } else result = -1; return result; }
// ============================================================================= // 功能:片选拉低,该函数运行必须获得总线信号量,即SPI_BusSemp,然后根据CS是否具有 // 自己的配置寄存器标志,判断是否需要配置寄存器。若csctrl标志为false,则每次CS // 使能时,都需要配置寄存器 // 参数:Dev,器件指针 // timeout,请求总线信号量超时时间,us // 返回:true,成功;false,失败 // ============================================================================= bool_t SPI_CsActive(struct tagSPI_Device *Dev,u32 timeout) { struct tagSPI_CB *SPI; tagSpiConfig spicfg; if(NULL == Dev) return false; SPI = (struct tagSPI_CB *)Rsc_GetParent(&Dev->DevNode); if(NULL == SPI) return false; if(Dev->AutoCs == false) //手动调用才有效 { if(false == Lock_SempPend(SPI->SPI_BusSemp,timeout)) //需要等待总线空闲 return false; //如果没有独立的CS参数配置寄存器,则每次操作都需要配置SPI参数配置寄存器, //因为多个CS共用同一套参数配置寄存器 if((SPI->MultiCsReg == false) && (SPI->CurrentDev != Dev)) { spicfg.CharLen = Dev->CharLen; spicfg.Mode = Dev->Mode; spicfg.Freq = Dev->Freq; SPI->pBusCtrl(SPI->SpecificFlag,CN_SPI_CS_CONFIG, (ptu32_t)Dev->Cs,(ptu32_t)&spicfg); } //如果每个CS都有独立的配置寄存器,则无需每次调用都配置,用户可通过调用pBusCtrl //控制CS相关的寄存器配置 SPI->CurrentDev = Dev; SPI->pCsActive(SPI->SpecificFlag,Dev->Cs); } return true; }
// ============================================================================= // 功能:RTC时间更新任务,由于Atmel芯片的RTC更新时间最长可能达到1秒因此,因此专门用一个低 // 优先级的任务作为更新RTC任务,以防占用其他线程的CPU时间 // 参数:无 // 返回:无 // ============================================================================= ptu32_t Rtc_UpdateTime(void) { while(1) { if(Lock_SempPend(pRtcSemp,CN_TIMEOUT_FOREVER)) { __Rtc_SetTime(UpdateTime); } } return 0; }
//----发送一帧数据--------------------------------------------------------------- //功能:发送一个数据包到以太网上 //参数:upsec,上层数据包(一个链表结构)的头指针 //返回:正常时为发送的字节数;错误时为-1 //----------------------------------------------------------------------------- s32 __hw_write_out(struct enet_send_section *upsec) { u16 dat; u32 i, len, times, totlen; struct enet_send_section* pt_ssec; // 请求DM9000A硬件操作的信号量,如果没有发出去,则返回 if (Lock_SempPend(semp_dm9000, 0) == true) { Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 totlen = 0; pt_ssec = upsec; ADDRW8(DM9000A_MWCMD); if (ehi.io == 0) // 16-bit { u8* pt_data; // 定义字节为8位的,下面进行强制转换 while (pt_ssec != NULL) { pt_data = (u8*)pt_ssec->data; len = pt_ssec->count; totlen += len; if ((ptu32_t)pt_data & 0x01) //判断指针是否双字节对齐 { for (i=0; i<len; i+=2) { dat = pt_data[i] + (pt_data[i+1]<<8); DATAW16(dat); } } else { times = (len+1)/2; for (i=0; i<times; i++) DATAW16(((u16*)pt_data)[i]); } pt_ssec = pt_ssec->next_data_ssection; } } else if (ehi.io == 1) // 32-bit { } else if (ehi.io == 2) // 8-bit { } if (totlen > 0) { iow(DM9000A_TXPLH, (totlen>>8) & 0xff); iow(DM9000A_TXPLL, totlen & 0xff); iow(DM9000A_NSR, 0x2c); // 清除状态寄存器 iow(DM9000A_TCR, ior(DM9000A_TCR) | 0x01); //发送数据到以太网上 // 等待发送完成 // NSR中TX1END及TX2END(发送完成) // ISR中PTM(发送完成) times = 100; // 相当等待于3S while (!(ior(DM9000A_NSR) & 0x0C) || !(ior(DM9000A_ISR) & 0x02)) { if (times == 0) { dm9000a_reset_to_new(); break ; } times--; Djy_DelayUs(10); } }
//----从DM9000A中读出所有数据---------------------------------------------------- //功能:把DM9000A中的所有数据都读取出来,这些数据包会组织在lst链表中。 //参数:lst,数据包的接收链表头指针 //返回:数据包的接收链表头指针(可能与输入的lst不同) //----------------------------------------------------------------------------- struct enet_rcv_packet *__hw_read_in(struct enet_rcv_packet *lst) { u32 tmp; u32 len; u32 totlen = 0; static u32 times = 0; struct enet_rcv_packet *nlst = NULL; // 请求DM9000A硬件操作的信号量,等待5S秒如果没有发出去,则返回 if (Lock_SempPend(semp_dm9000, 0) == true) { // 接收过程中如果有中断发生,中断响应函数读 写DM9000的其他寄存器会打断接收过程。 Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 ior(DM9000A_MRCMDX); // dummy read tmp = (u8)DATAR16(); if (tmp == 0x01) // 第一个字节读出为01h { switch (ehi.io) { case ENUM_DM9000A_IO_16BIT: // 16-bit while (tmp == 0x01) { len = dump_data16(lst, &nlst); if (len == -1) { dm9000a_reset_to_new(); totlen = 0; } else { totlen += len; // 试读下一帧数据,若为01h则继续读数,若为0则表示没有有效数据 ADDRW8(DM9000A_MRCMDX); tmp = (u8)DATAR16(); lst = nlst; } } __hw_ctrl(enum_enet_hw_ctrl_clear_rx_int); // 清除接收中断 break; case ENUM_DM9000A_IO_32BIT: // 32-bit break; case ENUM_DM9000A_IO_8BIT: // 8-bit break; default: break; } } else if (tmp != 0) { times++; if (times > 5) { debug_dm9000a_read_reg(NULL); } dm9000a_reset_to_new(); totlen = 0; if (times > 5) { debug_dm9000a_read_reg(NULL); times = 0; } } Int_RestoreAsynLine(cn_int_line_enet); // 打开DM9000A的外部中断 Lock_SempPost(semp_dm9000); } return nlst; }
bool_t debug_dm9000a_read_reg(char *param) { char *word, *next_param; int i; u32 reg = 0xFFFF; // 提取为SOCKET号 if (param) { next_param = param; word = Sh_GetWord(next_param, &next_param); reg = __sh_atol(word); word = Sh_GetWord(next_param, &next_param); if(word != NULL) { printf("\r\n参数错误\r\n"); return false; } } if (Lock_SempPend(semp_dm9000, 10000*mS) == true) { Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 if (reg != 0xFFFF) { printf("\r\n读取DM9000A的【%4x】寄存器:", reg); printf("\r\n %4x:%4x", reg, ior(reg)); } else { printf("\r\n读取DM9000A的【所有】寄存器:"); printf("\r\n"); for (i=0; i<=0x1f; i++) { printf("\r\n %4x:%4x", i, ior(i)); } printf("\r\n"); for (i=0x22; i<=0x25; i++) { printf("\r\n %4x:%4x", i, ior(i)); } printf("\r\n"); for (i=0x28; i<=0x34; i++) { printf("\r\n %4x:%4x", i, ior(i)); } printf("\r\n"); i = 0x38; printf("\r\n %4x:%4x", i, ior(i)); i = 0x39; printf("\r\n %4x:%4x", i, ior(i)); printf("\r\n"); i = 0x50; printf("\r\n %4x:%4x", i, ior(i)); i = 0x51; printf("\r\n %4x:%4x", i, ior(i)); printf("\r\n"); i = 0xF0; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF1; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF2; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF4; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF5; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF6; printf("\r\n %4x:%4x", i, ior(i)); i = 0xF8; printf("\r\n %4x:%4x", i, ior(i)); printf("\r\n"); for (i=0xFA; i<=0xFF; i++) { printf("\r\n %4x:%4x", i, ior(i)); } } printf("\r\n"); Int_RestoreAsynLine(cn_int_line_enet); // 打开DM9000A的外部中断 Lock_SempPost(semp_dm9000); } return true; }
// ============================================================================= // 功能: 启动读时序,启动读时序的过程为:器件地址(写)、存储地址(写)、器件地址(读) // 当器件地址(读)完成时,需打开中断,重新配置寄存器为接收模式,之后将会发生 // 接收数据中断,在中断中将接收到的数据调用IIC_PortWrite写入缓冲,接收到len字 // 节数的数据后,释放信号量iic_semp // 参数: specific_flag,个性标记,本模块内即IIC寄存器基址 // dev_addr,器件地址的前7比特,已将内部地址所占的bit位更新,该函数需将该地址左 // 移一位增加增加最后一位读/写比特; // mem_addr,存储器内部地址,即发送到总线上的地址,该地址未包含放在器件地址上的 // 比特位; // maddr_len,存储器内部地址的长度,字节单位,未包含在器件地址里面的比特位; // len,接收的数据总量,接收数据的倒数第一字节,即count-1,停止产生ACK信号,当接 // 收的字节数为count时,产生停止时序,并释放信号量iic_semp; // iic_semp,读完成时,驱动需释放的信号量(缓冲区信号量) // 返回: TRUE,启动读时序成功,FALSE失败 // ============================================================================= static bool_t __IIC_GenerateReadStart(ptu32_t specific_flag, u8 dev_addr, u32 mem_addr, u8 maddr_len, u32 length, struct tagSemaphoreLCB *iic_semp) { volatile tagI2CReg *reg; u8 mem_addr_buf[4]; u32 Recv_Times=0; u32 Recv_Index=0; u32 i=0; u32 Single_Length_Max=0; Single_Length_Max=0xFE-maddr_len; Recv_Times=(u32)(length/Single_Length_Max); Recv_Index=Recv_Times; if (length % Single_Length_Max!=0) { Recv_Times++; } for(i=0;i<Recv_Index;i++) { if(specific_flag == CN_IIC_REGISTER_BADDR0) { if(i!=Recv_Index-1) { IntParamset0.TransTotalLen = Single_Length_Max; IntParamset0.TransCount = 0; IntParamset0.pDrvPostSemp = iic_semp; //iic_bus_semp mem_addr=mem_addr+i*Single_Length_Max; } else { IntParamset0.TransTotalLen = length-(Recv_Index-1)*Single_Length_Max; IntParamset0.TransCount = 0; IntParamset0.pDrvPostSemp = iic_semp; //iic_bus_semp } } else { return false; } fill_little_32bit(mem_addr_buf,0,mem_addr); reg=(tagI2CReg *)specific_flag; _IIC_IntDisable(reg); SETBIT(reg->rTWIMITR, TWIEN); //generate START //step1:首先发送start信号 SETBIT(reg->rTWIMCTL,TWIMEN); //MASTER MODE //step2:发送器件地址,最低位置0. if(__TWI_WaitForTwiFree()>=0) { //reg->rTWIMADDR = TWI_ADDR_GET(dev_addr); //device addr reg->rTWIMADDR =dev_addr; reg->rTWIMCTL = 0xFF<<6; //clean MCTL reg //step3:判断是否收到ACK. if(__TWI_WaitForAck(0)==0) { //step4:若收到从机发的ACK,则开始发存储地址. if(__TWI_WriteAddr(reg, mem_addr_buf,maddr_len)==0); { //step5:若成功发送完存储地址,接着发送一个Repeat Start信号 SETBIT(reg->rTWIMCTL,TWIRSTART); //step6:发送器件地址,最低位置1. SETBIT(reg->rTWIMCTL,TWIMDIR); reg->rTWIMADDR = TWI_ADDR_GET(dev_addr); //step7:开中断 _IIC_IntEnable(reg); if(i!=Recv_Index-1) { Lock_SempPend(iic_semp,CN_TIMEOUT_FOREVER); } else { return true; } } } } } return false; }
// ============================================================================= // 功能:数据传送函数,完成数据的发送和接收。该函数完成的功能如下: // 1.若器件驱动为了避免组包的麻烦,可先发命令再发送数据,分多次调用,多次调用前 // 后被CSActive和CsInactive函数包裹; // 2.根据Dev查找所属SPI总线; // 3.若缓冲区大于发送字节数,则直接将数据填入缓冲区; // 4.若为阻塞发送,则等待总线信号量,若为非阻塞,则等待buf信号量; // 5.发生超时或错误时,拉高CS并释放信号量 // 参数:Dev,器件指针 // spidata,SPI数据结构体 // block_option,阻塞选项,为true时,表明最后一次传输为阻塞方式,否则为非阻塞 // timeout,超时参数,us // 返回:返回发送状态,超时或错误或无错误 // ============================================================================= s32 SPI_Transfer(struct tagSPI_Device *Dev,struct tagSPI_DataFrame *spidata, u8 block_option,u32 timeout) { struct tagSPI_CB *SPI; // struct semaphore_LCB *spi_semp; s32 result ; u32 written=0; u32 base_time = 0,rel_timeout = timeout; if(NULL == Dev) return CN_SPI_EXIT_PARAM_ERR; SPI = (struct tagSPI_CB *)Rsc_GetParent(&Dev->DevNode);//查找该器件属于哪条总线 if(NULL == SPI) return CN_SPI_EXIT_PARAM_ERR; base_time = (u32)DjyGetTime(); //若配置需自动片选,则本函数内部需拉低片选 if(Dev->AutoCs == true) { if(false == Lock_SempPend(SPI->SPI_BusSemp,timeout)) //需要等待总线空闲 { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_bus_timeout; } __SPI_AutoCsActive(SPI,Dev); } Lock_SempPend(SPI->SPI_BlockSemp,0); //相当于重置信号量 //禁止调试或未登记pTransferTxRx,使用轮询方式通信 if((Djy_QuerySch() == false) || (SPI->pTransferTxRx == NULL) || (SPI->Flag & CN_SPI_FLAG_POLL)) { if(SPI->pTransferPoll != NULL) { SPI->pTransferPoll(SPI->SpecificFlag,spidata->SendBuf,spidata->SendLen, spidata->RecvBuf,spidata->RecvLen,spidata->RecvOff); if(Dev->AutoCs == true) __SPI_AutoCsInactive(SPI,Dev->Cs); result = CN_SPI_EXIT_NOERR; } goto exit_from_no_err; } if(spidata->RecvLen) block_option = true; //接收数据自动转为阻塞 SPI->SPI_Buf.Offset = 0; //发送前先清空缓冲区 SPI->Frame = *spidata; SPI->BlockOption = block_option; //如果非阻塞方式,且缓冲区够大,则直接写入缓冲区 //若不是,则先发送调用者提供的缓冲区,直到剩余字节数能够填充到缓冲区 if((!block_option) && (spidata->SendLen <= SPI->SPI_Buf.MaxLen)) { memcpy(SPI->SPI_Buf.pBuf,spidata->SendBuf,spidata->SendLen); written = spidata->SendLen; } //调用启动时序的回调函数 if(true == SPI->pTransferTxRx(SPI->SpecificFlag, spidata->SendLen, spidata->RecvLen, spidata->RecvOff )) { rel_timeout = (u32)DjyGetTime(); if(rel_timeout - base_time < timeout) rel_timeout = timeout - (rel_timeout - base_time); else { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_timeout; } //需要等待的情况:1.阻塞发送;2.数据未全部填到缓冲区 if((true == block_option) || (written < spidata->SendLen)) { //等待中断函数释放信号量 if(!Lock_SempPend(SPI->SPI_BlockSemp,rel_timeout)) { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_timeout; } } result = CN_SPI_EXIT_NOERR; goto exit_from_no_err; }else { result = CN_SPI_EXIT_UNKNOW_ERR; goto exit_from_timeout; } exit_from_timeout: if(Dev->AutoCs == true) //自动片选时,返回前需拉低片选 { __SPI_AutoCsInactive(SPI,Dev->Cs); } exit_from_bus_timeout: exit_from_no_err: return result; }