This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
is there any equivalent for attributes like IRAM_ATTR for TM4C129X for ISR, especially for the UART interrupt?
Hi,
What toolchains do you find the IRAM_ATTR being supported? I'm not familiar with the IRAM_ATTR if this is something specific to a 3rd party toolchains or device. In the TI Arm compiler, you can use SET_CODE_SECTION or CODE_SECTION pragma to map a piece of your code (e.g. a function) to a user defined section. In the linker, you can allocate that user defined section to a MEMORY region which can be in the RAM. This is something that might come close to to IRAM_ATTR. You will need to copy that piece of code from the flash to the SRAM as part of your application in order for that code to be run from the SRAM. Please refer to the assembler/linker user's guide about the Load and Run addresses. Having said that, why would you want to run your UART ISR from the SRAM? I don't really see any significant benefit at all. Yes, I agree SRAM reads and writes are a one cycle operation at 120Mhz. However, with the pipelining circuitry, running code from the flash is almost one cycle as well due to the built-in 4x256 prefetch buffers.
TI Arm Compiler user's guide: https://www.ti.com/lit/pdf/spnu151. Search for CODE_SECTION or SET_CODE_SECTION.
TI Assembler/Linker user's guide: https://www.ti.com/lit/ug/spnu118u/spnu118u.pdf. Go to section 3.1.1 about Load and Run addresses.
3.1.1 Load and Run Addresses Consider an embedded device for which the program's load image is burned onto EPROM/ROM. Variable data in the program must be writable, and so must be located in writable memory, typically RAM. However, RAM is volatile, meaning it will lose its contents when the power goes out. If this data must have an initial value, that initial value must be stored somewhere else in the load image, or it would be lost when power is cycled. The initial value must be copied from the non-volatile ROM to its run-time location in RAM before it is used. See Section 8.8 for ways this is done. The load address is the location of an object in the load image. The run address is the location of the object as it exists during program execution. An object is a chunk of memory. It represents a section, segment, function, or data. The load and run addresses for an object may be the same. This is commonly the case for program code and read-only data, such as the .const section. In this case, the program can read the data directly from the load address. Sections that have no initial value, such as the .bss section, do not have load data and are considered to have load and run addresses that are the same. If you specify different load and run addresses for an uninitialized section, the linker provides a warning and ignores the load address. The load and run addresses for an object may be different. This is commonly the case for writable data, such as the .data section. The .data section's starting contents are placed in ROM and copied to RAM. This often occurs during program startup, but depending on the needs of the object, it may be deferred to sometime later in the program as described in Section 3.5. Symbols in assembly code and object files almost always refer to the run address. When you look at an address in the program, you are almost always looking at the run address. The load address is rarely used for anything but initialization. The load and run addresses for a section are controlled by the linker command file and are recorded in the object file metadata.
hi,
thank you for the clarifications, I mentioned IRAM_ATTR just as an indication, and yes, it is correct what you did understand, it is all about running a code with the maximum possible speed, I have specified the UART for a reason, we are seeing a lot overrun errors reported by the UART error flag, my intention is to run the UART ISR inside the SRAM, which is theoretically faster than internal flash.
I did manage to use the #pragma CODE_SECTION(".fastRAM")
but then the debugger was not able to flash the processor, I also noticed that the new binary file is smaller in size, and has factions of bytes, comparing to the original bin file without the CODE_SECTION pragma.
what am I missing here?
I have specified the UART for a reason, we are seeing a lot overrun errors reported by the UART error flag, my intention is to run the UART ISR inside the SRAM, which is theoretically faster than internal flash.
I kind of doubt the overrun is due to slower execution of the ISR. Agree that flash is a bit slower than the SRAM (when your code is not sequential) but that difference is not enough to cause a overrun. What baud rate are you using? I suppose you are running at a fast baud rate. In any case, UART is a relatively slow device compared to the CPU.
I will suggest you check the below.
- Do you have any higher priority interrupts that preempt the UART interrupts?
- Not sure if you process the incoming UART data directly inside the ISR. That is normally not the best way of processing the data. You should process the data outside of ISR. When you receive an UART interrupt, in the ISR, you should clear the interrupt flag and set a flag and quickly exit the ISR. In your main code, wait for the flag to set. Once the flag is set, you process the UART data and then clear the flag. When you spend too much time inside an ISR, it will prevent the next UART interrupt from being serviced and the interrupt is thus lost. This is probably one likely reason that you get an overrun. Keep the ISR short is the foundation of a RTOS for real time operations. You want to mimic RTOS's interrupt handling for fast ISR response.
- Check if you have enabled the FIFO. The RX FIFO is 16x8 deep. If you enable FIFO, it can buffer data before generating interrupt. This is especially helpful if you have fast baud rate. Also make sure you set up the threshold at which to generate interrupts. The threshold can be set up for 1/8, 1/4, 1/2, and etc.
I did manage to use the #pragma CODE_SECTION(".fastRAM")
but then the debugger was not able to flash the processor, I also noticed that the new binary file is smaller in size, and has factions of bytes, comparing to the original bin file without the CODE_SECTION pragma.
I don't know what is wrong. I'm not an expert in using CODE_SECTION. What error did you get on the screen if you are unable to flash the processor?
I will suggest you first put a small piece of test code in the CODE_SECTION and see if it works. What do you have for your linker command file? Which memory did you allocate your .fastRAM to? Did you set up the run and load addresses? Did you copy your .flashRAM code from flash to RAM? Please answer all the questions so I can forward your problem to our compiler experts for assistance.
hi, thanks for the fast response,
regarding the UART overrun, what you have mentioned in absolutely correct, and I did already implemented a circular buffer that process the data outside the ISR, I'm using 115200 baud rate, we have a high quantity of data traveling in our system, the issue is we have minimum message length of one byte, so we have the threshold set to 1 byte of data.
my last solution was to try the RAM option.
I tried to configure the memory is mapped as the following:
SECTIONS
{
.intvecs: > INTERNAL_FLASH_START_ADDR
.text : > FLASH
.const : > FLASH
.cinit : > FLASH
.pinit : > FLASH
.init_array : > FLASH
.vtable : > INTERNAL_RAM_START_ADDR
.bss : > SRAM
.stack : > SRAM
.data : > SRAM
.sysmem : > SRAM
.fastRam:>SRAM
}
the compilation successes with no issue, but I couldn't flash the processor, I think the debugger is failing to write/verify the bin file.
not sure of that partition of the memory is usable for the purpose I want.
the XDS200 try to flash the binary file with no success.
the size of binary output when the of the #pragma CODE_SECTION(".fastRAM") is smaller than the old one.
here is the error message from the debugger:
Hi,
As I mentioned in the other new thread you just created, your linker file is not sufficient to run code from RAM. Have you gone through the user's guide about the Load and Run addresses? I have replied you in the other post with the following notes. Also we should communicate using one thread for the same topic if your issue is not resolved. There is no need to open several threads for the same topic.
For sure your linker file is insufficient to realize running code from SRAM. As I mentioned in the other post as well the linker user's guide has explained, you don't just allocate .fastRAM: > SRAM. This is not enough. The debugger is not going to program your .flashRAM code to RAM. It is not that simple. This is why I asked you to look at the Load and Run address description in the user's guide. You must also copy the code from the Load address to the Run address. That copy routine must be performed by your application, not the debugger programmer.
Below is an example that I have seen people using the SET_CODE_SECTION.
extern uint32_t _mode7_ld_start;
extern uint32_t _mode7_rn_start;
extern uint32_t _mode7_code_size;
#pragma SET_CODE_SECTION(".l2flash_mode7")
void yourFunction ()
{
}
#pragma SET_CODE_SECTION()
In the linker file:
.l2flash_mode7 : {} palign(32)
RUN = RAM, LOAD = FLASH0,
LOAD_START(_mode7_ld_start),
RUN_START(_mode7_rn_start),
LOAD_SIZE(_mode7_code_size)
You MUST copy your code from the Load address to the Run address. Again, would you please refer to the user's guide for Load and Run addresses.
3.1.1 Load and Run Addresses Consider an embedded device for which the program's load image is burned onto EPROM/ROM. Variable data in the program must be writable, and so must be located in writable memory, typically RAM. However, RAM is volatile, meaning it will lose its contents when the power goes out. If this data must have an initial value, that initial value must be stored somewhere else in the load image, or it would be lost when power is cycled. The initial value must be copied from the non-volatile ROM to its run-time location in RAM before it is used. See Section 8.8 for ways this is done. The load address is the location of an object in the load image. The run address is the location of the object as it exists during program execution. An object is a chunk of memory. It represents a section, segment, function, or data. The load and run addresses for an object may be the same. This is commonly the case for program code and read-only data, such as the .const section. In this case, the program can read the data directly from the load address. Sections that have no initial value, such as the .bss section, do not have load data and are considered to have load and run addresses that are the same. If you specify different load and run addresses for an uninitialized section, the linker provides a warning and ignores the load address. The load and run addresses for an object may be different. This is commonly the case for writable data, such as the .data section. The .data section's starting contents are placed in ROM and copied to RAM. This often occurs during program startup, but depending on the needs of the object, it may be deferred to sometime later in the program as described in Section 3.5. Symbols in assembly code and object files almost always refer to the run address. When you look at an address in the program, you are almost always looking at the run address. The load address is rarely used for anything but initialization. The load and run addresses for a section are controlled by the linker command file and are recorded in the object file metadata.