Forum: Mikrocontroller und Digitale Elektronik stm32f2xxx: Pointer auf Flashadresse


von stm32user (Gast)


Lesenswert?

Guten Morgen,

in der Hauptapplikation soll auf die Adresse 0x08010800 im Flash 
gesprungen werden. Hier liegt eine Abbildung von der 
Flashupdatefunktion.
Dieser Bereich habe ich allerdings im Linkerskript nicht angegeben.
Die Hauptapplikation liegt im Flash zwischen 0x08000000 und 0x0800FFFF.
Ab Adresse 0x08010000 bis 0x080FFFF liegt die neue Firmware. In diesem 
Bereich ab der der Adresse 0x08010800 bis 0x08011000 liegt die 
Flashupdatefunktion.

Variante 1:
1
typedef void (*pFunction)(void);
2
pFunction Jump_To_Application;
3
unsigned long JumpAddress;
4
5
JumpAddress = *(unsigned long*) (0x08010800);
6
Jump_To_Application = (pFunction) JumpAddress;
7
Jump_To_Application();

Variante 2:
1
typedef void (*JUMP_TO_FLASH_UPDATE_FUNCTION)(void);
2
3
register JUMP_TO_FLASH_UPDATE_FUNCTION flashloader_entry;
4
flashloader_entry = * ((JUMP_TO_FLASH_UPDATE_FUNCTION *)0x08010800);
5
flashloader_entry();

Leider ist es mir bisher nicht gelungen zu der Adresse 0x08010800 per 
Funktionspointer zu springen. Was mache ich da falsch?

von stm32user (Gast)


Lesenswert?

Korrektur:

>Ab Adresse 0x08010000 bis 0x0801FFFF liegt die neue Firmware.

von Dr. Sommer (Gast)


Lesenswert?

stm32user schrieb:
> flashloader_entry = * ((JUMP_TO_FLASH_UPDATE_FUNCTION *)0x08010800);
Du dereferenzierst ja die Adresse, d.h. lädst den Funktionspointer, der 
ab der Stelle 0x08010800 gespeichert ist. Nur dass sich da kein 
Funktionspointer befindet, sondern die Funktion selber. Du brauchst 
einfach nur
1
flashloader_entry = (JUMP_TO_FLASH_UPDATE_FUNCTION )0x08010800;
Einfacher wäre natürlich im Linkerscript
1
flashloader_entry = 0x08010800
Und dann im C-Code eine gewöhnliche Funktionsdeklaration.
Und warum willst du den Compiler per "register" am Optimieren hindern? 
Das wird vermutlich ohnehin ignoriert.

von stm32user (Gast)


Lesenswert?

Hall Dr. Sommer,

vielen Dank für deine schnelle Antwort.

Wenn ich dies so teste, dann wird in den HardFaultHandler gesprungen. 
Das Programm hängt.
1
JumpAddress = (unsigned long)(0x08010800);
2
Jump_To_Application = (pFunction) JumpAddress;
3
Jump_To_Application();

Im Debugger (IAR) habe ich die Flashbereiche überprüft.

FlashUpdateFunktion --> 0x08000800 bis 0x08001000
FlashUpdateFunktion --> 0x08010800 bis 0x08011000

Beide sind identisch. Warum funktioniert das Springen zu der Adresse 
0x08010800 nicht?

von stm32user (Gast)


Lesenswert?

Linkerskript:
1
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
2
/*-Memory Regions-*/
3
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
4
define symbol __ICFEDIT_region_ROM_end__   = 0x08008000;
5
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
6
define symbol __ICFEDIT_region_RAM_end__   = 0x20002000;
7
8
export symbol __ICFEDIT_region_RAM_start__; 
9
export symbol __ICFEDIT_region_RAM_end__;
10
11
/*-Sizes-*/
12
define symbol __ICFEDIT_size_cstack__ = 0x400;
13
define symbol __ICFEDIT_size_heap__   = 0x200;
14
/**** End of ICF editor section. ###ICF###*/
15
16
17
define memory mem with size       = 4G;
18
define region ROM_region           = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
19
define region RAM_region           = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
20
define region FLASH_DO_UPDATE_FUNCTION  = mem:[from 0x08000800 to 0x08001000];
21
22
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__ { };
23
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__   { };
24
25
initialize by copy { readwrite };
26
do not initialize  { section .noinit };
27
do not initialize  { section FLASH_DO_UPDATE };
28
29
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
30
31
place in ROM_region            { readonly };
32
place in RAM_region            { readwrite, block CSTACK, block HEAP };
33
place in FLASH_DO_UPDATE_FUNCTION   { section FLASH_DO_UPDATE };

[c]
#pragma default_function_attributes = @ "FLASH_DO_UPDATE"
void FlashUpdate(void)
{
 ...
}
#pragma default_function_attributes =
[c]

von Dr. Sommer (Gast)


Lesenswert?

Oh gerade Vergessen, es muss 0x08010801 sein, damit die Funktion im 
Thumb Mode ausgeführt wird; die Cortex-M haben schließlich keinen 
ARM-Mode.

von stm32user (Gast)


Lesenswert?

Funktioniert immer noch nicht. Der HardFaultHandler ausgeführt.
1
typedef void (*pFunction)(void);
2
pFunction Jump_To_Application;
3
unsigned long JumpAddress;
4
5
__disable_interrupt();
6
7
/* Jump to user application */
8
JumpAddress = (unsigned long)(0x08010801);
9
Jump_To_Application = (pFunction) JumpAddress;
10
Jump_To_Application();

von stm32user (Gast)


Lesenswert?

Die andere Alternative mit der pragma Anweisung location, funktioniert 
auch nicht.
1
#pragma location = "FLASH_DO_UPDATE"
2
void FlashUpdate(void)
3
{
4
 ...
5
}

von sushi (Gast)


Lesenswert?

Ich hab das auch mal aufm STM32F4 gemacht. hier mein Code.
1
#define APPLICATION_ADDR    ((uint32_t)0x08008000)
2
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDR + 4);
3
Jump_To_Application = (pFunction) JumpAddress;
4
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDR);
5
Jump_To_Application();

Das war damals aus einem einfachen Bootloader. Der hat vorher den neuen 
Code in den Flash kopiert und dann dort ausgeführt.

Der Code läuft wohl auch aufm STM32F2xxxx:
Beitrag "STM32F2 - Flashloader"

von stm32user (Gast)


Lesenswert?

Das funktioniert auch nicht. HardFaultHandler wird ausgeführt.

0x08000000 und 0x0800FFFF --> In diesem Bereich liegt die 
Hauptapplikation.
0x08000800 und 0x08001000 --> In der Hauptapplikation liegt die 
FlashUpdate Funktion.

Die neue Firmware wird im oberen Flashbereich abgelegt:
0x08010000 und 0x0801FFFF --> Neue Firmware.
0x08010800 und 0x08011000 --> In der neuen Firmware ist die gleiche 
FlashUpdate Funktion enthalten.

Sobald die neue Firmware im Flasgbereich abgelegt wurde, soll via 
Funktionspointer auf die Flashadresse 0x08010800 gesprungen werden. 
Leider funktioniert dies nicht.

von stm32user (Gast)


Lesenswert?

Es muss doch möglich sein via Funktionspointer auf die Flashadresse 
0x08010800 zu springen ohne das der HardFaultHandler ausgelöst wird.

von stm32user (Gast)


Lesenswert?

Nachtrag: Im map-File ist kein Eintrag FLASH_DO_UPDATE zusehen.

Auszug aus dem map-File:
1
"A1":  place at 0x08000000 { ro section .intvec };
2
"P1":  place in [from 0x08000000 to 0x08008000] { ro };
3
"P2":  place in [from 0x20000000 to 0x20002000] { rw, block CSTACK, block HEAP };

von sushi (Gast)


Lesenswert?

Versetzt du auch den Stackpointer mit __set_MSP()?
Liegt die Adresse und der Funktionsdummy auf dem Stack oder sind die 
global?

Hat die neue Firmware auch eine Vektortabelle dabei?
Wenn ja, musst du die auch laden

von Steffen R. (steffen_rose)


Lesenswert?

stm32user schrieb:
> Wenn ich dies so teste, dann wird in den HardFaultHandler gesprungen.
> Das Programm hängt.JumpAddress = (unsigned long)(0x08010800);
> Jump_To_Application = (pFunction) JumpAddress;
> Jump_To_Application();

Diese Variante sollte deiner Beschreibung nach funktionieren (mit der +1 
für Thumb). Sicher, dass der Hardfault aufgrund des Sprunges und nicht 
erst in der angesprungenen Funktion ausgelöst wird? Am besten im 
Assembler den Sprung debuggen.

Arbeitet die Updatefunktion schon in deinem Test? D.h. wird das aktuelle 
Programm gelöscht?

Fängt auf 0x8010800 überhaupt die Funktion an oder hast Du hier die 
Interruptvektortabelle für die Hardfaults usw. während die Applikation 
gelöscht ist? Dann wäre eher das Beispiel vom Bootloader relevant.

von dotm (Gast)


Lesenswert?


von stm32user (Gast)


Lesenswert?

Die neue Firmware (+ Vektortabelle usw.) liegt im Flashadressraum: 
0x08010000 - 0x0801FFFF

Was musste ich tun?

Vektortabelle/Interrupttabelle neu setzen?
Wie springe ich dan auf die Flashadresse: 0x08010800?

von sushi (Gast)


Lesenswert?

1
/* Initialize user application's Stack Pointer and Vector Table*/
2
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x08010000);
3
__set_MSP(*(__IO uint32_t*) 0x08010000);

Das setzt die Vector Tabelle und den StackPointer.
Wahrscheinlich hat die zweite Firmware die Tabelle an der Adresse.

Danach dann auf die Firmware springen.

Hast du auch die Firmware richtig verlinkt? Also so, dass die davon 
ausgeht auf deinen gewünschten Adressbereich zu sein?
Sonst kann es sein, dass deine Funktion eine nicht vorhandene Funktion 
im alten Adressbereich aufrufen will und das zum HardFault führt.

von Steffen R. (steffen_rose)


Lesenswert?

Ich dachte, die neue Firmware soll umkopiert werden. D.h. sie würde auf 
der oberen Adresse garnicht laufen. Damit kann die Vectortabelle von 
dort auch nicht genutzt werden.

> Wie springe ich dan auf die Flashadresse: 0x08010800?

Die Frage ist noch immer, was dort steht. Und ob der Hardfault direkt 
bei dem Assembler Jumpbefehl auftritt. Ich gehe davon aus, dass er erst 
später innerhalb deiner Funktion auftritt.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi,

um eine neue Firmware an anderer Stelle zu starten, musst du das VTOR 
(Vect Table Offset Reg) sowie den Stack Pointer neu setzen, dann ins 
Programm springen.

Die Infos dazu findest du an Offset 0x00 (Stack Pointer) und 0x04 
(ResetVect) deines Firmware-Images.

Für armcc  (für gcc entsprechend):
1
// <h> Vector Table
2
// =================
3
//
4
//   <o0> Vector Table Base Address
5
//   <i> Vector Table Base Address
6
//   <i> Default: 0x90000
7
//
8
#define NVIC_VectTab_FLASH       0x90000
9
#define SP_OFFS                     0
10
#define RESET_OFFS                  4
11
// </h>
1
  void (*user_code_entry)(void);
2
  register uint32_t MSP __ASM("msp");
3
4
  // ggf. Firmwareupdate von SD-Karte ins Flash
5
  ...
6
7
  //__disable_irq();
8
  //__DSB();
9
  //__ISB();
10
  SCB->VTOR       = NVIC_VectTab_FLASH;
11
  user_code_entry = (void(*)(void))((*((unsigned int *)(NVIC_VectTab_FLASH + RESET_OFFS))));
12
  MSP             = *((unsigned int *)(NVIC_VectTab_FLASH + SP_OFFS));
13
14
  user_code_entry();

Ich habe das so aufgezogen, dass mein Bootloader in den ersten 64k Flash 
liegt, und keines Updates bedarf. Darüber liegt die Firmware. Diese wird 
immer vom Bootloader gestartet.
Schlägt das FW Update aus irgendeinem Grund fehl, muss in meinem Falle 
nur die SD Karte aus dem Gerät genommen, und auf diese das 
Firmware-Image kopiert werden.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Dein Jump in den Hard Fault schaut danach aus, als wenn der SP nicht 
geändert wurde, und der Library Init damit daneben geht.

Generell habe ich auf Cortex-M immer dabei:
1
void HandleFault(void)
2
{
3
#ifdef _DEBUG
4
  int i;
5
#endif
6
  
7
  LED_PWR_OFF;
8
  LED_OUTSTATE_ON;  
9
  
10
#ifdef _DEBUG
11
  while(1) {
12
    LED_PWR_ON;
13
    LED_OUTSTATE_ON;
14
    for(i=0; i<0xffff; i++) __NOP();
15
    LED_PWR_OFF;
16
    LED_OUTSTATE_OFF;
17
    for(i=0; i<0xffff * 10; i++) __NOP();
18
  }  
19
#else
20
  NVIC_SystemReset();
21
#endif
22
}
23
24
void HardFault_Handler(void)
25
{
26
  TextOut("\n\n !!! HARD FAULT !!!");
27
  HandleFault();
28
}
29
30
void MemManage_Handler (void)
31
{
32
  TextOut("\n\n !!! MEM MANAGE FAULT !!!");
33
  HandleFault();
34
}
35
36
void BusFault_Handler  (void)
37
{
38
  TextOut("\n\n !!! BUS FAULT !!!");
39
  HandleFault();
40
}
41
42
void UsageFault_Handler(void)
43
{
44
  TextOut("\n\n !!! USAGE FAULT !!!");
45
  HandleFault();
46
}

TextOut() geht wahlweise in den ITM Ch.0 (wenn ein Debugger 
angeschlossen ist), oder in den 4kB BackLog Buffer der Karte, den man 
dann mit Telnet auslesen kann.

von stm32user (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

bisher bin funktioniert das ganze noch nicht so wie es soll.

Um eine Funktion in einen bestimmten Flashbereich zu legen, welche 
Linkeranweisung müsste verwendet werden?

Variante 1:
1
#pragma location = "FLASH_DO_UPDATE"
2
void FlashUpdate(void)
3
{
4
 ...
5
}

Variante 2:
1
#pragma section= "FLASH_DO_UPDATE"
2
void FlashUpdate(void)
3
{
4
 ...
5
}

Variante 3:
1
#pragma default_function_attributes = @ "FLASH_DO_UPDATE"
2
void FlashUpdate(void)
3
{
4
 ...
5
}
6
#pragma default_function_attributes =

Wie müsste ich in nun meinem Fall den Resetvector und den Stackpointer 
setzen?
1
// Neue Firmware liegt im Flash ab der Adresse 0x08010000
2
   
3
__disable_interrupt();
4
5
typedef void (*pFunction)(void);
6
pFunction Jump_To_Application;
7
unsigned long JumpAddress;
8
9
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x08010000);
10
__set_MSP(*(__IO uint32_t*) 0x08010000);
11
12
JumpAddress = (unsigned long)(0x08010800 + 4);
13
Jump_To_Application = (pFunction) JumpAddress;
14
Jump_To_Application();

von sushi (Gast)


Lesenswert?

Ist die Datei das Linker-File der neuen Firmware? Wenn ja, dann ist doch 
ganz klar wo der Fehler liegt:

Du sagst der neuen Firmware dort, dass sie auf 0x08000000 läge. Das tut 
sie aber nicht. Dann springst du dennoch in eine Funktion der neuen 
Firmware und die ruft wahrscheinlich eine vorhandene Funktion auf, die 
sie aber nicht finden kann, weil sie im Bereich der alten Firmware 
sucht.
Du musst die neue Firmware so linken, dass sie ihre Vektortabelle auch 
dort ablegen will wo du sie hin tust.

Dann läuft der Sprung und alles is hübsch.

Die "+4" brauchst du vermutlich dabei nicht, weil die im Bootloader nur 
notwendig war, weil man damit direkt in die Reset ISR springt. Da du 
deine Funktion callen willst, reicht ein "+0" oder "+1" wegen ThumbCode.

von Steffen R. (steffen_rose)


Lesenswert?

stm32user schrieb:
> Um eine Funktion in einen bestimmten Flashbereich zu legen, welche
> Linkeranweisung müsste verwendet werden?

Die meisten hier gegebenen Tipps gehen davon aus, dass deine neue 
Software auf dem höheren Flashbereich gestartet werden soll. Kannst Du 
bitte mal darauf eingehen?

Oder soll die alte Firmware gelöscht werden und die neue umkopiert 
werden? So, wie ich dein Problem vertehe?

Könntest Du dies kurz klarstellen?

Wenn Du umkopieren willst, würde deine Lösung so nicht funktionieren und 
auch die meisten der Tipps fehlschlagen.
(clib wird gelöscht, keine zweite Vektortabelle an aeiner sinnvollen 
Stelle)

von stm32user (Gast)


Lesenswert?

Das Linker-File ist von der Hauptapplikation. In dieser Hauptapplikation 
gibt es eine FlashUdpdate-Funktion (0x08000800-0x08001000).
Die neue Firmware wird ab der Flashadresse 0x08010000 abgelegt. Die neue 
Firmware ist quasi die abgeänderte Hauptapplikation mit der 
FlashUpdate-Funktion. Da liegt ebenfalls die FlashUpdate-Funktion, 
allerdings ab der Flashadresse 0x08010800 bis 0x08011000. Nun soll 
nachdem die neue Firmware ab der Flashadresse 0x08010000 abgelegt wurde, 
die FlashUdpade-Funktion von der Flashadresse 0x08010800 ausgeführt 
werden.

von stm32user (Gast)


Lesenswert?

Ok ich habe es ausvergessen zu erwähnen. Ich möchte die neue Firmware in 
den unteren Flashbereich 0x08000000 kopieren. Sorry!!!

von stm32user (Gast)


Lesenswert?

Dieses Vorgehen habe ich bereits auf einem anderen Derivate erfolgreich 
am Laufen.

von sushi (Gast)


Lesenswert?

OK. Das war ein guter Einwand von Steffen ;)
Jetzt habe ich dich definitiv verstanden. Dennoch bleibt das Problem 
leider das gleiche.
Du springst in die FLASH_UPDATE Funktion der neuen Firmware und willst 
kopieren. Diese Funktionen zum kopieren findet er dort aber nicht, weil 
die eigentlich auf den ursprünglichen Bereich verlinkt sind.

Welcher Controller war das denn in deinem vorherigen Projekt?

Wie sieht denn deine "neue" FlasH_Update() aus?


Ich persönlich hätte eine Update-Routine geschrieben, die in einem ganz 
anderen Bereich liegt und sich nach "Rollout" nicht mehr ändert. Diese 
Funktionen kopieren die neue Firmware, die sich dann bei Bedarf noch 
weitere Module laden kann. Somit umgehst du das Problem und kommst der 
Architektur eines Bootloaders näher. Ich hab aber nicht weiter über mein 
Vorgehen nachgedacht o.Ä.. Das war nur eine spontane Meinung.

von stm32user (Gast)


Lesenswert?

Ich möchte allerdings keine zwei Applikationen. Eine für die 
Hauptapplikation und die andere für den Flashloader. Es soll alles aus 
einer Datei möglich sein.

Wenn ich die Flashloader Kopierfunktion in einen anderen Flashbereich 
lege, dann wird beim Koiervorgang auch die Vektrotabelle sowie der 
Stackpointer überschrieben. Wie soll das dann gehen?

von Steffen R. (steffen_rose)


Lesenswert?

Die Updatefunktion ist der kritische Punkt!

Sie muß an der Stelle stehen, wo sie auch aufgrund des Linkerfiles 
stehen soll. Ansonsten ist sie nicht ausführbar.

Die Updatefunktion darf keine Referenzen auf die alte Firmware haben. 
Diese wird ja gelöscht. Daher am besten direkte Registerzugriffe machen 
und nicht Funktionen aus der STLib aufrufen. Der werden wohl auch auf 
den Bereich der alten Firmware liegen. Oder auch die benötigten 
Funktionen mit in die Update-Sektion legen. Doch dann wird es haarig. 
Dann mußt Du alle Referenzen prüfen.
Außerdem nehme ich stark an, dass Du beim umkopieren auch die neue 
Updatefunktion auf die alte schreibst. Daher müßte deine Updatefunktion 
eigentlich in den RAM.

Ob deine Updatefunktion an der richtigen Stelle abgelegt wurde kannst Du 
im Mappingfile prüfen. Die Syntax ist für jeden Compiler anders. Daher 
weiß ich grad nicht, welche für den IAR korrekt ist.
Oder Du schaust Dir diese im Flash an.

Eine Interruptvektortabelle hat deine Funktion nicht. Daher am besten 
alle Antworten hierzu erstmal ignorieren. Dein Design ist aber unschön, 
da du im Fehlerfall keinen Handler hast und auch deine Kopieraktion 
nicht erneut angestoßen wird.

Du must die Updatefunktion ab 0x08000800 nehmen. Da nur diese für diesen 
Bereich übersetzt wurde.

==================================
Überdenke bitte dein Konzept. Es macht viele Probleme. Daher nutzen 
eigentlich alle einen (selbstgeschriebenen) Bootloader.
Im einfachsten Fall prüft er nur, ob eine neue Software auf dem oberen 
Bereich liegt und kopiert diese um. Wenn alles gut ist löscht er die 
neue..

Danach oder wenn nichts zu tun ist, springt dieser in die Applikation.

Da dieses der einfachere Weg ist und üblich, kamen hierzu auch die 
meisten Hinweise.

von sushi (Gast)


Lesenswert?

ACK
Sehe ich alles genauso.

Du kannst deinen "Bootloader" in deiner Applikation integrieren. So wird 
dann beim Start deiner Firmware geprüft ob eine neue Version vorhanden 
ist. Dann kopiert der die neue Firmware an die richtige Stelle und gut 
ist.

Was macht denn die "neue" flash_update() mehr als die alte?

Wahrscheinlich nichts... Deswegen füge in der main() die Updateprüfung 
ein und dann hast du auch kein zusätzliches Programm im Flash liegen

von Steffen R. (steffen_rose)


Lesenswert?

Ich hatte eher an einen unabhängigen Bootloader gedacht
- mit einer eigenen Vectortabelle
- mit einer eigenen clib
- mit einer eigenen STLib (u.a. Flashroutinen)

Also das übliche, was man unter einem Bootloader versteht.
Damit hat der Bootloader noch alles, wenn die eigentliche Applikation 
gelöscht wird.

von sushi (Gast)


Lesenswert?

Ja, aber das will er ja nicht ;)

von stm32user (Gast)


Lesenswert?

Meine erste Variante habe ich so gelöst, das ich eine zusätzliche 
Applikation entwickelt habe, die nichts anderes macht als die Daten im 
RAM (neue Firmware) in den unteren Flashspeicher 0x08000000 kopiert.
Wie könnte ich diese Applikation mit der Hauptapplikation verlinken?
Ich möchte nur einmal den Debugger anwerfen und nicht zweimal.

von Steffen R. (steffen_rose)


Lesenswert?

Muss er! Ansonsten ziehts ihn die Füße weg beim Löschen.
Außer, er kopiert alles in den RAM, was er braucht.

Aber das Projekt, bei dem das schonmal geklappt hat, würde mich 
interessieren. Speziell die Lösung mit der Updatefunktion. Kann ja fast 
nur der NXP mit seinen Flashfunktionen im ROM gewesen sein.

von Steffen R. (steffen_rose)


Lesenswert?

stm32user schrieb:
> Wie könnte ich diese Applikation mit der Hauptapplikation verlinken?
Kompliziert. Die Updatefunktion und alles, worauf sie referenziert, muss 
an eine Stelle, die nicht überschrieben wird.

Deine damalige Lösung war schon die richtige.

> Ich möchte nur einmal den Debugger anwerfen und nicht zweimal.
Man kann meist die Symbole des zweiten Programms nachladen. Meist muss 
dieses aber schon im Flash stehen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.