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.
I am using TivaC TM4C123 MCU. I am trying to send data serially through one pin and a synchronized clock through another pin. Here is an illustration:
I used Timer0 module for the serial data and Timer1 for the clock. The frequency of the clock should be twice the data. Here is the important part of the code:
void DATA(long number, int iteration){ //number: data to be send serially long x=0; // iteration: number of bits to be send for(int y=0; y<iteration ; y++){ while((TIMER0->RIS & 0x00000001) != 1){} //wait until Timer0 times out x= number & (0x1<<y); //Get each bit individually if(x==(0X1<<y)) //If bit is 1 GPIOF->DATA |= (1<<1); //Make PF1 High else if(x==0X0) //If bit is 0 GPIOF->DATA &= 0XFD; //Make PF1 Low TIMER0->ICR |= (1<<0); //Reset Timer0 flag while((TIMER1->RIS & 0x00000001) != 1){} //wait until Timer1 times out GPIOF->DATA ^= (1<<2); //Toggle clock TIMER1->ICR |= (1<<0); //Reset Timer1 flag } } int main(){ GPIO_INIT(); // Initiate GPIO TIMER_INIT(); // Initiate Timers with Timer0= 1/2 Timer1 while (1){ DATA(0XAB01,16); // 0xAB01 16 bit data need to be send serially } }
There is a problem in this code, which is both of the data and the clock have the same frequency, which means that Timer0 or Timer1 are disabled.
To make my problem more clear and easy to understand. I wrote two simple codes with a graph for each of them. Here is the first code: I am using While loop
int main() { GPIO_INIT(); TIMER_INIT(); //Timer0= 1/2 Timer1 while (1){ while((TIMER0->RIS & 0x00000001) != 1){} //Wait for TIMER0 to time out GPIOF->DATA ^= (1<<1); //Toggle PF1 TIMER0->ICR |= (1<<0); //Reset TIMER0 flag while((TIMER1->RIS & 0x00000001) != 1){} //Wait for TIMER1 to time out GPIOF->DATA ^= (1<<2); // Toggle PF2 TIMER1->ICR |= (1<<0); //Reset TIMER1 flag } }
Here is the output I got:
Here is the 2nd code: I am using If condition
int main(){ GPIO_INIT(); TIMER_INIT(); //Timer0= 1/2 Timer1 while (1){ if((TIMER0->RIS & 0x00000001) == 1){ //If TIMER0 out timed out GPIOF->DATA ^= (1<<1); //Toggle PF1 TIMER0->ICR |= (1<<0); //Reset TIMER0 flag } if((TIMER1->RIS & 0x00000001) == 1){ //If TIMER1 timed out GPIOF->DATA ^= (1<<2); //Toggle PF2 TIMER1->ICR |= (1<<0); //Reset TIMER1 flag } } }
Here is the output:
Conclusion: When I used the if condition the two timers are working normally, but when I used While loop only one timer is working and the other timer is just using the same counts of the other.
Abdelrahman Tarief said:If my explanation of the problem is not clear, let me know.
May I commend you for an effective explanation - which includes the (always) helpful, Signal Timing Chart.
That said - I believe there are 2 "weaknesses" w/in your method of attack:
Some here - especially those in the Tech Biz - employ "KISS" to develop quickly, accurately, & w/the greatest chance of success. DRM & use of both Timers w/in a single Timer Module are "anti-KISS" and both are central w/in your posting... Would not "simplification" assist - both here - and (long) into the future? Few (points) attach to those choosing the (long & hard) path - when superior ones beckon...
Hi,
If you split a 32bit timer into two sub-timers, each sub-timer is now 16bits long, so you cannot fill up them with huge constants like 8000000 - you changed the initial posted code - this is I remember in your case.
Use API configuration function for that, and maybe explain what you try to do with your function, at this stage we cannot comment about.
Second cb1's suggestion to convert to TivaWare
Also
Abdelrahman Tarief said:GPIOF->DATA |= (1<<1);
Using structures and unions to interface with hardware is generally considered a bad idea.
Using bitfields to interface with hardware is generally considered a very, very bad idea.
Robert
The ARM Cortex Microcontroller Software Interface Standard (CMSIS) specifically uses header files with structures, unions and bitfields to overall hardware peripherals - see the examples in https://www.keil.com/pack/doc/CMSIS/SVD/html/svd__s_v_d_conv_pg.html. Note that the peripheral header files can be auto-generated from a schema, and that the generation program has the option of creating bitfield structures which are MISRA compliant, but not CMSIS compliant.Robert Adsett said:Using structures and unions to interface with hardware is generally considered a bad idea.Using bitfields to interface with hardware is generally considered a very, very bad idea.
I am curious to know why you consider such interfaces to hardware a bad idea.
Chester Gillon said:I am curious to know why you consider such interfaces to hardware a bad idea.
Basically it falls back to the language definition. Using structures is very tempting (especially to beginners) but the result of doing so depends on the compiler and sometimes even the compiler revision. More subtly sometimes it may depend on the silicon.
The language guarantees that the members of a struct will be allocated in order.
It does not guarantee
The second and third have the biggest effect. Generally the size is secondary. The compiler is free to choose whatever alignment for members is convenient subject only to the constraint that it cannot be different for different declarations of a struct. It can add space to align members or it can remove space between members. Different compilers for the same silicon can make different choices.
For access, the compiler can perform multiple accesses to read or write unaligned members, even reading and writing neighbouring members. I think it can do this for aligned members as well, think of two byte regesters that are close to one another. This has, in fact been a practical issue with some compilers on the ARM architecture where people have used the struct construct for I/O definition. The Cortex core may not allow this distinction but IIRC ARM7 cores could be compiled with allowing unaligned access, failing silently on unaligned access or faulting on unaligned access so if you forced a struct to be unaligned the result of using unaligned members could vary widely. Compilers have been known to change access methods to a struct based on optimization, sometimes accessing a byte wide structure by using the word and masking accordingly. This can mess up both read-only status registers (think interrupt acknowledge) and write only registers that share addresses with read only registers.
Compilers have added proprietary keywords and compile flags so that alignment can vary not only depending on the source but also the build system.
Basically if you start using structs for hw mapping you have to consult not only the source and micro documentation but also the build flags (especially if they vary by module) and compiler documentation and even then you may not catch all the dependencies. It becomes rather difficult when you come back to a project years later and is bad enough at the time. Even then you may not catch everything (how many compilers document how access changes with optimization?) and it may change when you update the compiler.
Unions really only add the caveat that there is no guarantee on the placement of the members or that you won't fault if you read one member after writing a different member. The first is rarely an issue when the members happen to share a size.
Robert
Bitfields start with the struct problems and add their own.
Chester Gillon said:bitfield structures which are MISRA compliant,
I had thought MISRA had explicitly banned bitfields for I/O access. I'm virtually certain they did on earlier versions, I've not read the latest.