Why do these arrangements of embedded c code perform so differently?

Background

I am working with and 8052 based microcontroller. I have an LCD and and encoder wheel hooked up. The user can navigate a menu displayed on the LCD by rotating and pressing the encoder wheel.

The rotation of the encoder wheel is interrupt based.

The direction the encoder wheel is being rotated (encoder_turn) is set inside of the encoder interrupt.

I call update_lcd() inside of a loop.

New Responsive Code

void update_lcd()                           
{

        //ENCODER TURN      
        switch(encoder_turn)
        {
            case RIGHT:
                 lcd_clear();
                 next_screen();
                 break;
            case LEFT:
                lcd_clear();
                previous_screen();
                break;
            default:
                break;
        }
 }

void next_screen()
{
    if(current_test_screen < screen5)
    {
        current_test_screen++;
    }

    draw_current_test_screen(); 
}

void draw_current_test_screen()
{
    switch(current_test_screen)
    {
        case screen1:
            draw_screen1();
            break;
        case screen2:
            draw_screen2();
            break;
        case screen3:
            draw_screen3();
            break;
        case screen4:
            draw_screen4();
            break;
        case screen5:
            draw_screen5();
            break;      
        default:
        break;
    }
}

Old Unresponsive Code

void update_lcd()                           
{

        //ENCODER TURN      
        switch(encoder_turn)
        {
            case RIGHT:
                 lcd_clear();
                 next_screen();
                 break;
            case LEFT:
                lcd_clear();
                previous_screen();
                break;
            default:
                break;
        }

        switch(current_test_screen)
        {
            case screen1:
                draw_screen1();
                break;
            case screen2:
                draw_screen2();
                break;
            case screen3:
                draw_screen3();
                break;
            case screen4:
                draw_screen4();
                break;
            case screen5:
               draw_screen5();
               break;       
            default:
               break;
       }


 }

void next_screen()
{
    if(current_test_screen < screen5)
    {
        current_test_screen++;
    }
}

The Question

Why is one responsive and the other completely useless?

When I say responsive I am referring to the fact that when I rotate the encoder the screen change is responsive. Both methods "work" but one is unacceptable from a usage standpoint.

Answers


Those two pieces of code are almost equivalent, apart from one very subtle difference.

If you try refactoring your old code to try make it look more like your new code, you find that your old code makes one extra function call. Look carefully at the difference:

void update_lcd()                           
{
        //ENCODER TURN      
        switch(encoder_turn)
        {
            case RIGHT:
                 lcd_clear();
                 next_screen();
                 break;
            case LEFT:
                lcd_clear();
                previous_screen();
                break;
            default:
                draw_current_test_screen();   // <--- your new code omits this call
                break;
        }
 }

Try taking your new code and adding that line and see if it causes the unresponsiveness problem.


Just a guess, but I suspect: Since the only thing you changed is the function nesting, encoder_turn is probably being cached by the optimizer. You need to mark encoder_turn as volatile, as the interrupt can occur and change its value at any time.


Need Your Help


About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.