|
|
  |
как работать с IAP? |
|
|
|
Jan 28 2009, 15:10
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(cornflyer @ Jan 28 2009, 17:26)  Кто-нибудь научился работать...
нашел как поставить внешний i2c eeprom.... A, что, кто-нибудь это (после чтения документации и многочисленных обсуждений на форуме ) не умеет  . А вообще смотря для чего, у меня I2C EEPROM почти всегда, не смотря на то, что и во FLASH многое что пишется (приложения, прошивки FPGA,.....).
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 29 2009, 12:47
|

Частый гость
 
Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729

|
на форуме нет внятного описания как работать с IAP, нет рабочего кода, только какие-то танцы с бубном  пробовал код с форума - то пишет, то не пишет... непонятно почему в самой документации на lpc2148 - только пару строк хотя я все делал как требуется: выключал прерывания вызывал функцию подготовки флеша потом писал туда массив байт из RAM'а выложи свой рабочий код, который пишет и читает внутреннюю FLASH через IAP
|
|
|
|
|
Jan 30 2009, 06:51
|

Частый гость
 
Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729

|
да, я читал application note AN10256 компилятор Keil, target опция USE THUMB MODE включена.... CODE /* * IAP In-System Application Programming */
#include <LPC21xx.H>
// Clock Frequency #define XTAL 12000000 // Oscillator Frequency
#ifdef BYPASS_IAP #define CPUCLK XTAL // CPU Clock without PLL #else #define CPUCLK (XTAL*4) // CPU Clock with PLL #endif
#define CCLK (XTAL / 1000) // CPU Clock without PLL in kHz
// Phase Locked Loop (PLL) definitions #define PLL_BASE 0xE01FC080 // PLL Base Address #define PLLCON_OFS 0x00 // PLL Control Offset #define PLLSTAT_OFS 0x08 // PLL Status Offset #define PLLFEED_OFS 0x0C // PLL Feed Offset #define PLLCON_PLLE 0x01 // PLL Enable #define PLLCON_PLLD 0x00 // PLL Disable #define PLLCON_PLLC 0x03 // PLL Connect(0x02) | PLL Enable #define PLLSTAT_PLOCK 0x0400 //1<<10 // PLL Lock Status
struct iap_in { unsigned int cmd; unsigned int par[4]; };
typedef void (*IAP)(struct iap_in *in, unsigned int *result); #define iap_entry ((IAP) 0x7FFFFFF1) // IAP entry point
/* Default Interrupt Function: may be called when interrupts are disabled */ void def_isr (void) __irq { ; }
#ifdef BYPASS_IAP /* * Switch CPU to PLL clock */ void start_pll (void) { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55
// Enable PLL MOV R3, #PLLCON_PLLE STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS]
// Wait until PLL Locked LDR R2, =PLLSTAT_PLOCK PLL_Loop: LDR R3, [R0, #PLLSTAT_OFS] CMP R3, R2 BEQ PLL_Loop
// Switch to PLL Clock MOV R2, #0x55 MOV R3, #PLLCON_PLLC STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] } }
/* * Switch CPU to standard XTAL */ void stop_pll(void) __arm { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55
// Disable PLL MOV R3, #PLLCON_PLLD STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] } }
#endif
/* * Convert 'addr' to sector number */ unsigned int get_secnum (void *addr) { unsigned int n;
n = ((unsigned int) addr >> 13) & 0x1F; // pseudo sector number
if (n >= (0x30000 >> 13)) { n -= 14; // high small 8kB Sectors ( } else if (n >= (0x10000 >> 13)) { n = 7 + (n >> 3); // large 64kB Sectors } return (n); // sector number }
/* * Erase Sector between 'start' and 'end' * Return: IAP error code (0 when OK) * NOTES: start needs to be a 256 byte boundary * size should be 256, 512, 1024 or 4089 */ unsigned int erase (void* start, void* end) { struct iap_in iap; // IAP input parameters unsigned int result[16]; // IAP results unsigned int save_VicInt; // for saving of interrupt enable register
save_VicInt = VICIntEnable; // save interrupt enable status VICIntEnClr = 0xFFFFFFFF; // disable all interrupts
#ifdef BYPASS_IAP stop_pll(); // IAP requires to run without PLL #endif
iap.cmd = 50; // IAP Command: Prepare Sectors for Write iap.par[0] = get_secnum (start); // start sector iap.par[1] = get_secnum (end); // end sector iap_entry (&iap, result); // call IAP function if (result[0]) goto exit; // an error occured?
iap.cmd = 52; // IAP command: Erase Flash iap.par[0] = get_secnum (start); // start sector iap.par[1] = get_secnum (end); // end sector iap.par[2] = CCLK; // CPU clock iap_entry (&iap, result); // call IAP function
exit:
#ifdef BYPASS_IAP start_pll(); // start PLL #endif
VICIntEnable = save_VicInt; // enable interrupts return (result[0]); }
/* * Program *data to flash_addr. number of bytes specified by size * Return: IAP error code (0 when OK) * Note: */ unsigned int program (void *flash_addr, void *data, unsigned int size) { struct iap_in iap; // IAP input parameters unsigned int result[16]; // IAP results unsigned int save_VicInt; // for saving of interrupt enable register
save_VicInt = VICIntEnable; // save interrupt enable status VICIntEnClr = 0xFFFFFFFF; // disable all interrupts
#ifdef BYPASS_IAP stop_pll(); // IAP requires to run without PLL #endif
iap.cmd = 50; // IAP Command: Prepare Sectors for Write iap.par[0] = get_secnum (flash_addr); // start sector iap.par[1] = iap.par[0]; // end Sektor iap_entry (&iap, result); // call IAP function if (result[0]) goto exit; // an error occured?
iap.cmd = 51; // IAP Command: Copy RAM to Flash iap.par[0] = (unsigned int) flash_addr; // destination-addr iap.par[1] = (unsigned int) data; // source-addr iap.par[2] = size; // number of bytes iap.par[3] = CCLK; // CPU clock iap_entry (&iap, result); // call IAP function
exit:
#ifdef BYPASS_IAP start_pll(); // start PLL #endif
VICIntEnable = save_VicInt; // enable interrupts return (result[0]); }
unsigned char vals[512];
void main (void) { unsigned int i;
unsigned int volatile start;
for (start = 0; start < 1000000; start++) { ; // wait for debugger connection (about 0.3 sec) }
VICDefVectAddr = (unsigned int) def_isr; // for spurious interrupts
for (i = 0; i < sizeof (vals); i++) { vals[i] = (unsigned char) i; }
program (0x30000, vals, sizeof (vals)); program (0x31000, vals, sizeof (vals)); program (0x32000, vals, sizeof (vals)); erase (0x30000, 0x31FFF); erase (0x32000, 0x33FFF);
while (1); }
|
|
|
|
|
Jan 30 2009, 08:48
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(cornflyer @ Jan 29 2009, 15:47)  на форуме нет внятного описания как работать с IAP, нет рабочего кода, только какие-то танцы с бубном  Никаких танцев при шатном использовании. Цитата ..непонятно почему На вопрос "почему" отвечает сам IAP возвращая коды ошибок, только вот Вы их анализировать не считаете нужным  . Начните с этого Цитата в самой документации на lpc2148 - только пару строк Вообще-то там целый раздел...
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 2 2009, 07:21
|

Частый гость
 
Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729

|
внутренний flash стоит использовать для хранения редкоменяющейся инфы... часто писать во внутренний flash - плохой стиль у него ресурс всего 100000 циклов записи.... запись через IAP занимает время, причем проц не обрабатывает прерывания.... если 100 раз в сутки приходица сохранять инфу - лучше писать во внешний eeprom у него ресурс 1000000 циклов вот например можно поставить i2c eeprom M24C64 код для чтения/записи приведен ниже: Код #include "lpc214x.h" /*-------------------------------------------------------------------------*/ #define SDA_BIT (1<<3)//for olimex board #define SCL_BIT (1<<2)//for olimex board #define I2C_ADDR (0x50)//I2C Slave Address /*-------------------------------------------------------------------------*/ void I2C_DELAY(void){ volatile z=1000; while(z) z--; } /*-------------------------------------------------------------------------*/ unsigned char I2C_SDA(void){ return (IOPIN0&SDA_BIT); } /*-------------------------------------------------------------------------*/ void I2C_SDA_HIGH(void){ IODIR0 &=~ SDA_BIT;//input } /* -------------------------------------------------------------------------*/ void I2C_SDA_LOW(void){ IOCLR0 = SDA_BIT; IODIR0 |= SDA_BIT;//output low } /*-------------------------------------------------------------------------*/ void I2C_SCL_HIGH(void){ IODIR0 &=~ SCL_BIT;//input } /*-------------------------------------------------------------------------*/ void I2C_SCL_LOW(void){ IOCLR0 = SCL_BIT; IODIR0 |= SCL_BIT;//output low } /*-------------------------------------------------------------------------*/ unsigned char i2c_send_byte(unsigned char b){ unsigned char result = 0; unsigned int i = 0; for(i=0;i<8;i++){ //Set Data if(b&0x80){// == 1000 0000 I2C_SDA_HIGH(); }else{ I2C_SDA_LOW(); } b = b<<1;//shift left by one position I2C_DELAY(); I2C_SCL_HIGH();//make clock pulse I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); } //Acknowledge I2C_SDA_HIGH(); I2C_DELAY(); I2C_SCL_HIGH();//make clock pulse I2C_DELAY(); if(I2C_SDA()){//check i2c slave acknowledge result = 1; }else{ result = 0; } I2C_SCL_LOW(); I2C_DELAY(); return result; } /*-------------------------------------------------------------------------*/ unsigned char i2c_write(unsigned int addr,unsigned char b){ unsigned char result = 0; //Initial state (stop condition) I2C_SCL_HIGH(); I2C_DELAY(); I2C_SDA_HIGH(); I2C_DELAY(); //Start (start condition) I2C_SDA_LOW(); I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); //Send i2c address if(i2c_send_byte(I2C_ADDR<<1)){//RW=0 result = 1; }else{ if(i2c_send_byte(addr>>8))result = 1;//high addr if(i2c_send_byte(addr))result = 1;//low addr if(i2c_send_byte(b))result = 1; } //Stop (stop condition) I2C_SDA_LOW(); I2C_DELAY(); I2C_SCL_HIGH(); I2C_DELAY(); I2C_SDA_HIGH(); I2C_DELAY(); return result; } /*-------------------------------------------------------------------------*/ void i2c_write_byte(unsigned int addr, unsigned char b){ unsigned char result = 1; while(result)result = i2c_write(addr,b); } /*-------------------------------------------------------------------------*/ void i2c_read_page(unsigned int addr, unsigned char *page_buff, unsigned int page_length){ unsigned char data_byte = 0; int b; //Initial state I2C_SCL_HIGH(); I2C_DELAY(); I2C_SDA_HIGH(); I2C_DELAY(); //Start (start condition) I2C_SDA_LOW(); I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); //Send address i2c_send_byte(I2C_ADDR<<1);//RW=0 i2c_send_byte(addr>>8);//high addr i2c_send_byte(addr);//low addr //Start (start condition) I2C_SCL_HIGH(); I2C_DELAY(); I2C_SDA_LOW(); I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); i2c_send_byte((I2C_ADDR<<1)|0x01);//RW = 1 while(page_length){//read page I2C_SDA_HIGH(); for(b=8;b--;){ I2C_DELAY; I2C_SCL_HIGH(); I2C_DELAY(); data_byte = (data_byte<<1)|((I2C_SDA())?0x01:0x00); I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); } *page_buff = data_byte; page_buff++; data_byte = 0; page_length--; //Acknowledge if(page_length) I2C_SDA_LOW(); else I2C_SDA_HIGH(); I2C_DELAY(); I2C_SCL_HIGH(); I2C_DELAY(); I2C_DELAY(); I2C_SCL_LOW(); I2C_DELAY(); } //Stop (stop condition) I2C_SDA_LOW(); I2C_DELAY(); I2C_SCL_HIGH(); I2C_DELAY(); I2C_SDA_HIGH(); I2C_DELAY(); }
|
|
|
|
|
Feb 2 2009, 07:46
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(cornflyer @ Feb 2 2009, 10:21)  вот например можно поставить i2c eeprom M24C64 код для чтения/записи приведен ниже: А почему софтовый I2C???
|
|
|
|
|
Feb 2 2009, 08:22
|
Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937

|
По поводу IAP можно посмотреть здесь: http://www.tnkernel.com/usb_fw_upgrader.html (usb-fwu-1-0-1-lpc214x.zip -> fwu_asm.s) По поводу I2C - здесь:
|
|
|
|
|
Feb 2 2009, 11:17
|

Частый гость
 
Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729

|
преимущества софтового i2c :- софтовый i2c меньше занимает, работает без глюков  (смотри еррату на lpc2148) - SDA и SCL можно на любые ноги повесить мой личный опыт показывает что код, написанный на все случаи жизни - работает медленно, глючит и много жрет ресурсов.... поэтому я стараюсь кодить только то, что нужно для решения поставленной задачи
|
|
|
|
|
Feb 2 2009, 12:48
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(cornflyer @ Feb 2 2009, 14:17)  софтовый i2c меньше занимает, работает без глюков  (смотри еррату на lpc2148) Смотреть нечего - уже ДЕСЯТКИ лет I2C на любых Филипсовских контролерах никаких errata и глюков не имеет, является отлитым в бронзе стандартом. И, как Вам показалось, заработавший copy-paste из интернету софтового I2C не повод изрекать глупости про "глюки", "ресурсы" и "медленность".
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|