void ti89_put_byte(uint32_t adr, uint8_t arg) { // RAM access if(IN_BOUNDS(0x000000, adr, 0x1fffff)) { put_b(tihw.ram, adr, RAM_SIZE_TI89 - 1, arg); } // FLASH access else if(IN_BOUNDS(0x200000, adr, 0x5fffff)) { FlashWriteByte(adr, arg); } // memory-mapped I/O else if(IN_BOUNDS(0x600000, adr, 0x6fffff)) { io_put_byte(adr, arg); } // memory-mapped I/O (hw2) else if(IN_RANGE(adr, 0x700000, IO2_SIZE_TI89)) { io2_put_byte(adr, arg); } return; }
/******************************************************************** 函数功能:FLASH写命令。 入口参数:Val:要写的命令值。 返 回:无。 备 注:没有片选,必须在其他更高层的函数负责片选。 ********************************************************************/ void FlashWriteCommand(uint8 Cmd) { FlashSetCle(); //选择为命令 FlashSetPortAsOut(); FlashWriteByte(Cmd); FlashSetPortAsIn(); FlashClrCle(); }
void main(void) { uint8_t ui1; start_main: LCD_init(); DELAY(100); LCD_cmd(LCD_CMD_CUR_10); DELAY(100); LCD_WR_LINE(0, 0, "Hello World 1"); DELAY(100); FlashWriteByte (0xF000, 0x1); FlashWriteByte (0xF001, 0x2); FlashWriteByte (0xF002, 0x3); FlashWriteByte (0xF003, 0x4); ui1 = FlashReadByte(0xF000); LCD_WR("Hello World "); LCD_wrchar('0'+ui1); DELAY(10); ui1 = FlashReadByte(0xF001); LCD_WR("Hello World "); LCD_wrchar('0'+ui1); DELAY(10); ui1 = FlashReadByte(0xF002); LCD_WR("Hello World "); LCD_wrchar('0'+ui1); DELAY(10); ui1 = FlashReadByte(0xF003); LCD_WR("Hello World "); LCD_wrchar('0'+ui1); DELAY(10); goto start_main; }
/******************************************************************** 函数功能:读FLASH的ID号。 入口参数:Buf:保存ID号的缓冲区。 返 回:无。 备 注:无。 ********************************************************************/ void FlashReadId(uint8 *Buf) { uint8 i; FlashClrCe(); FlashWriteCommand(0x90); FlashSetAle(); //ALE置高,选择为地址 FlashSetPortAsOut(); //设置端口为输出状态 FlashWriteByte(0); //写一字节数据 FlashSetPortAsIn(); //设置端口为输入 FlashClrAle(); //ALE置低 for(i=0;i<5;i++) //读5字节的ID { FlashReadByte(Buf[i]); } FlashSetCe(); }
/******************************************************************** 函数功能:往FLASH写入二字节地址的函数。 入口参数:Addr:要写入的字节地址。 返 回:无。 备 注:没有片选,必须在其他更高层的函数负责片选。只写地址低位 ********************************************************************/ void FlashWriteAddr2Byte(uint32 Addr) { uint i; //只需要低11位 Addr=Addr&(FLASH_PAGE_SIZE-1); FlashSetAle(); //ALE置高,选择为地址 FlashSetPortAsOut(); //设置端口为输出状态 for(i=0;i<2;i++) //写入二字节的地址 { FlashWriteByte(Addr); //写一字节数据 Addr>>=8; } FlashSetPortAsIn(); //设置端口为输入 FlashClrAle(); //ALE置低 }
/******************************************************************** 函数功能:往FLASH写入二字节页地址的函数。 入口参数:Addr:要写入的字节地址。 返 回:无。 备 注:没有片选,必须在其他更高层的函数负责片选。 ********************************************************************/ void FlashWritePageAddr(uint32 Addr) { uint i; //计算页地址 Addr/=FLASH_PAGE_SIZE; FlashSetAle(); //ALE置高,选择为地址 FlashSetPortAsOut(); //设置端口为输出状态 for(i=0;i<2;i++) //写入四字节的地址 { FlashWriteByte(Addr); //写一字节数据 Addr>>=8; } FlashSetPortAsIn(); //设置端口为输入 FlashClrAle(); //ALE置低 }
/******************************************************************** 函数功能:往FLASH写入四字节地址的函数。 入口参数:Addr:要写入的字节地址。 返 回:无。 备 注:没有片选,必须在其他更高层的函数负责片选。注意地址中间的0。 ********************************************************************/ void FlashWriteAddr4Byte(uint32 Addr) { uint i; //注意:该FLASH的地址中间有5bit必须置0 //并将高16位左移5位 Addr=((Addr<<5)&(~0xFFFF))|(Addr&0x07FF); FlashSetAle(); //ALE置高,选择为地址 FlashSetPortAsOut(); //设置端口为输出状态 for(i=0;i<4;i++) //写入四字节的地址 { FlashWriteByte(Addr); //写一字节数据 Addr>>=8; } FlashSetPortAsIn(); //设置端口为输入 FlashClrAle(); //ALE置低 }
void WriteBufferRemainder(){ //any data remaining in the output buffer is written uint16_u outInt16; outInt16.val = currentRecordNumber; if (writeBufferIndex == 0){ currentPageAddress -= 1; FlashWriteByte(currentPageAddress,0,WRITE_COMPLETE_REC_END); loggingState = UPDATE_FIRST_PAGE; return; } writeBuffer[0] = WRITE_STARTED_REC_END; writeBuffer[1] = outInt16.buffer[0]; writeBuffer[2] = outInt16.buffer[1]; for(uint16_t i = writeBufferIndex; i < 256; i++){ writeBuffer[i] = 0xFF; } writeBufferIndex = 0; FlashWritePage(currentPageAddress,writeBuffer); loggingState = COMPLETE_LAST_PAGE; }
void ti89t_put_byte(uint32_t adr, uint8_t arg) { // RAM access if(IN_BOUNDS(0x000000, adr, 0x03ffff) || IN_BOUNDS(0x200000, adr, 0x23ffff) || IN_BOUNDS(0x400000, adr, 0x43ffff)) { put_b(tihw.ram, adr, 0x03ffff, arg); } // FLASH access else if(IN_BOUNDS(0x800000, adr, 0xbfffff)) { FlashWriteByte(adr, arg); } // memory-mapped I/O else if(IN_BOUNDS(0x600000, adr, 0x6fffff)) { io_put_byte(adr, arg); } // memory-mapped I/O (hw2) else if(IN_RANGE(adr, 0x700000, IO2_SIZE_TI89T)) { io2_put_byte(adr, arg); } // memory-mapped I/O (hw3) else if(IN_RANGE(adr, 0x710000, IO3_SIZE_TI89T)) { io3_put_byte(adr, arg); } return; }
/******************************************************************** 函数功能:往FLASH中写一个扇区(FLASH_SECTOR_SIZE字节)。 入口参数:Addr: 字节地址;pBuf:保存数据的缓冲区;Remain:预计接下来还需要写多少扇区 返 回:写入的状态。0:成功。非0:失败。 备 注:当Remain不为0时,当前页以及该块内剩余部分将不会回写! 如果数据传输结束,应该将Remain置0,将数据写回。 ********************************************************************/ uint32 FlashWriteOneSector(uint32 Addr, uint8 * pBuf, uint32 Remain) { uint32 i; uint32 SwapPageAddr; FlashClrCe(); //选中芯片 if(Addr>FLASH_MAX_SECTOR_ADDR)return 1; //如果地址超出范围,则返回失败代码1,越界 Addr=FlashAddrRemap(Addr); //重新影射地址 if((Addr&(~(FLASH_PAGE_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_PAGE_SIZE-1)))) //如果跨page { if(FlashNeedWriteBack) //如果前面写了数据,则需要将当前读出的page写回 { if(FlashWritePage()&0x01) //写入失败 { Addr=FlashDealBadBlock(Addr-FLASH_PAGE_SIZE,3)+FLASH_PAGE_SIZE; //坏块处理 } } if((Addr&(~(FLASH_BLOCK_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_BLOCK_SIZE-1)))) //如果跨block,则需要擦除新的块, { //在擦除之前,要先将原来的块复制到交换区,并且将该块前面部分数据写回 //该函数除了将整块数据复制到交换区以外,并且还将擦除掉原来的块,然后将前面部分复制回原来的块 Addr=FlashCopyBlockToSwap(Addr); } //从交换区中读出对应的一页 FlashWriteCommand(0x00); FlashWriteAddr4Byte(FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1))); FlashWriteCommand(0x35); FlashWait(); //随机写 FlashWriteCommand(0x85); FlashWriteAddr4Byte(Addr); //写4字节地址 FlashSetPortAsOut(); //总线设置为输出口 for(i=0;i<FLASH_SECTOR_SIZE;i++) { FlashWriteByte(pBuf[i]); } FlashSetPortAsIn(); //总线设置为输入口 FlashNeedWriteBack=1; //需要写回 } else //没有超过一页地址,则直接写数据 { //随机写 FlashWriteCommand(0x85); FlashWriteAddr2Byte(Addr); FlashSetPortAsOut(); //总线设置为输出口 for(i=0;i<FLASH_SECTOR_SIZE;i++) { FlashWriteByte(pBuf[i]); } FlashSetPortAsIn(); //总线设置为输入口 FlashNeedWriteBack=1; //需要写回 } FlashCurrentWriteSectorAddr=Addr; //保存本次地址 if(Remain==0) //剩余扇区数为0,不会再写了,需要写回 { if(FlashNeedWriteBack) //如果前面写了数据,则需要将当前读出的page写回 { if(FlashWritePage()&0x01) //写入失败 { Addr=FlashDealBadBlock(Addr,3); //坏块处理 } } //计算剩余页数 Remain=(((Addr+FLASH_BLOCK_SIZE)&(~(FLASH_BLOCK_SIZE-1)))-(Addr&(~(FLASH_PAGE_SIZE-1))))/FLASH_PAGE_SIZE-1; //计算在交换块中的起始页地址 SwapPageAddr=FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1)); for(i=0;i<Remain;i++) //将该块内保存在交换块中剩余部分页的数据复制回该块 { Addr+=FLASH_PAGE_SIZE; //从下一页开始写 SwapPageAddr+=FLASH_PAGE_SIZE; if(0x01==(FlashCopyPage(SwapPageAddr,Addr)&0x01)) //如果复制失败 { Addr=FlashDealBadBlock(Addr,2); //处理坏块 } } FlashNeedWriteBack=0; //清除需要写回标志 FlashCurrentWriteSectorAddr=-1; } FlashSetCe(); //释放FLASH芯片 return 0; }
/******************************************************************** 函数功能:保存坏块表到FLASH的特定位置。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void FlashSaveBadBlockTable(void) { uint32 i,j,k,Sum; for(i=0;i<FLASH_BLOCKS_TABLE;i++) //标志为准备擦除 { FlashWriteCommand(0x80); FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*(i+1) - FLASH_PAGE_SIZE); FlashSetPortAsOut(); //总线设置为输出口 FlashWriteByte(0x00); //将第一字节设置为0,表示准备擦除 //剩余字节写0xFF for(j=1;j<FLASH_PAGE_SIZE;j++) { FlashWriteByte(0xFF); } FlashWritePage(); //写页 } for(i=0;i<FLASH_BLOCKS_TABLE;i++) //将坏块表写入这三块 { FlashEraseBlock(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*i); //擦除一块 FlashWriteCommand(0x80); FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*i); //写入第一块的开始位置 FlashSetPortAsOut(); //总线设置为输出口 FlashWriteByte(0x00); //将第1字节设置为0 FlashWriteByte(0x55); //将第2字节设置为0x55 FlashWriteByte(0xAA); //将第3字节设置为0xAA FlashWriteByte(0xFF); //将第4字节设置为0xFF Sum=0x1FE; //接着写坏块数量,并统计校验和 FlashWriteByte((FlashBadBlocksCount>>24)&0xFF); Sum+=(FlashBadBlocksCount>>24)&0xFF; FlashWriteByte((FlashBadBlocksCount>>16)&0xFF); Sum+=(FlashBadBlocksCount>>16)&0xFF; FlashWriteByte((FlashBadBlocksCount>>8)&0xFF); Sum+=(FlashBadBlocksCount>>8)&0xFF; FlashWriteByte((FlashBadBlocksCount)&0xFF); Sum+=(FlashBadBlocksCount)&0xFF; j=8; //写了8字节 //保存坏块表 for(k=0;k<sizeof(FlashBadBlockTable[0][0])*FLASH_BAD_BLOCKS_REMAP*2;k++) { if(0==(j&(FLASH_PAGE_SIZE-1))) //如果超过了页,则需要重新写新页 { FlashWritePage(); //写页 FlashWriteCommand(0x80); FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*i + j); FlashSetPortAsOut(); //总线设置为输出口 } Sum+=((uint8 *)FlashBadBlockTable)[k]; //求校验和 FlashWriteByte(((uint8 *)FlashBadBlockTable)[k]); //写一字节 j++; } //保存重影射区的状态表 for(k=0;k<sizeof(FlashRemapBlockStatus[0])*FLASH_BAD_BLOCKS_REMAP;k++) { if(0==(j&(FLASH_PAGE_SIZE-1))) //如果超过了页,则需要重新写新页 { FlashWritePage(); //写页 FlashWriteCommand(0x80); FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*i + j); FlashSetPortAsOut(); //总线设置为输出口 } Sum+=((uint8 *)FlashRemapBlockStatus)[k]; //求校验和 FlashWriteByte(((uint8 *)FlashRemapBlockStatus)[k]); //写一字节 j++; } for(;0!=(j&(FLASH_PAGE_SIZE-1));j++) //将剩余部分写入0xFF { FlashWriteByte(0xFF); } FlashWritePage(); //写页 //已完成写状态及校验和写入到该块的倒数第二页 FlashWriteCommand(0x80); FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR + FLASH_BLOCK_SIZE*(i+1) - 2*FLASH_PAGE_SIZE); FlashSetPortAsOut(); //总线设置为输出口 FlashWriteByte(0x00); //将第一字节设置为0,表示已经写入 //将校验和取反加1,这样累加结果就为0 Sum=(~Sum)+1; //写校验和 FlashWriteByte((Sum>>24)&0xFF); FlashWriteByte((Sum>>16)&0xFF); FlashWriteByte((Sum>>8)&0xFF); FlashWriteByte((Sum)&0xFF); //剩余字节写0xFF for(j=5;j<FLASH_PAGE_SIZE;j++) { FlashWriteByte(0xFF); } FlashWritePage(); //写页 } }
void LoggingStateMachine(){ static uint16_t nextBlockAddress = 0; static uint8_t pageCount = 0; uint16_u outInt16; switch(loggingState){ case CHECK_4K: if(VerifyWriteReady() == false){ break; } if (FlashGetByte((nextBlockAddress + pageCount),0) != 0xFF){ loggingState = ERASE; break; } pageCount++; if(pageCount == 16){ pageCount = 0; loggingState = WRITE_READY; } break; case ERASE: if(VerifyWriteReady() == false){ break; } FlashEraseBlock4k(nextBlockAddress); loggingState = WRITE_READY; break; case WRITE_READY: if(VerifyWriteReady() == false){ break; } loggingReady = true; if (startNewLog == true){ endCurrentLog = false; startNewLog = false; startOfRecordDataToFlash = true; loggingState = START_NEW_LOG; break; } if (endCurrentLog == true){ logEnabled = false; endCurrentLog = false; startNewLog = false; loggingState = END_CURRENT_LOG; loggingReady = false; break; } break; case COMPLETE_PAGE: if(VerifyWriteReady() == false){ break; } FlashWriteByte(currentPageAddress,0,WRITE_COMPLETE); currentPageAddress += 1; if (currentPageAddress > 0x3FFF){ currentPageAddress = 0; } if ((currentPageAddress & 0x000F) == 0x000F){ loggingState = CHECK_4K; pageCount = 0; nextBlockAddress = (currentPageAddress & 0xFFF0) + 0x0010; if (nextBlockAddress > 0x3FF0){ nextBlockAddress = 0; } break; } loggingState = WRITE_READY; break; case START_NEW_LOG: if(VerifyWriteReady() == false){ break; } outInt16.val = currentRecordNumber; writeBuffer[0] = WRITE_STARTED_REC_START; writeBuffer[1] = outInt16.buffer[0]; writeBuffer[2] = outInt16.buffer[1]; writeBuffer[3] = 0xFF; writeBuffer[4] = 0xFF; writeBuffer[5] = 0xFF; FlashWritePartialPage(currentPageAddress,0,6,writeBuffer); writeBufferIndex = 6; loggingState = WRITE_READY; logEnabled = true; loggingReady = false; break; case END_CURRENT_LOG: if(VerifyWriteReady() == false){ break; } WriteBufferRemainder(); break; case COMPLETE_LAST_PAGE: if(VerifyWriteReady() == false){ break; } FlashWriteByte(currentPageAddress,0,WRITE_COMPLETE); loggingState = UPDATE_FIRST_PAGE; break; case UPDATE_FIRST_PAGE: if(VerifyWriteReady() == false){ break; } outInt16.val = currentPageAddress; writeBuffer[0] = 0x00; writeBuffer[1] = outInt16.buffer[0]; writeBuffer[2] = outInt16.buffer[1]; FlashWritePartialPage(currentRecordAddress,3,3,writeBuffer); loggingState = BOUND_CHECK; break; case BOUND_CHECK: if(VerifyWriteReady() == false){ break; } writePageStarted = false; loggingReady = false; currentPageAddress += 1; currentRecordAddress = currentPageAddress; if (currentPageAddress > 0x3FFF){ currentPageAddress = 0; } if ((currentPageAddress & 0x000F) == 0x000F){ loggingState = CHECK_4K; pageCount = 0; nextBlockAddress = (currentPageAddress & 0xFFF0) + 0x0010; if (nextBlockAddress > 0x3FF0){ nextBlockAddress = 0; } break; } loggingState = WRITE_READY; break; } }