Esempio n. 1
0
// This thread blinks a circle on the display every second as a heartbeat
static PT_THREAD(protothread_blink(struct pt *pt)) {
    PT_BEGIN(pt);
        while(1) {
            //draw circle
            tft_fillCircle(xc, yc, 4, ILI9340_GREEN);
            //yield time 1 second
            PT_YIELD_TIME_msec(500);
            //erase circle
            tft_fillCircle(xc, yc, 4, ILI9340_BLACK);
            //yield time 1 second
            PT_YIELD_TIME_msec(500);
	}
    PT_END(pt);
}
Esempio n. 2
0
//method to remove a ball from the linked list and attach
void deleteBall(ball *delete_this){	
	if(iterator->next != NULL)
        iterator = iterator->next;	
    if(current_balls == 1) {
        initial_ball = NULL;
        end_ball = NULL;
    }
	//if we need to delete initial ball
	else if (initial_ball == delete_this){
		initial_ball = delete_this -> next;	
        initial_ball->prev = NULL;
	}
	//if we need to delete end ball
	else if (end_ball == delete_this){
		end_ball = delete_this -> prev;
		end_ball->next = NULL;
	}
	//if it's a middle ball
	else{
		(delete_this->next)->prev = delete_this->prev;
		(delete_this->prev)->next = delete_this->next;
	}
	tft_fillCircle(fix2int16(delete_this->xc), fix2int16(delete_this->yc), RADIUS, ILI9340_BLACK);
	free(delete_this);
    delete_this = NULL;
    current_balls--;
	
}//function deleteBall
Esempio n. 3
0
//==================== Calculate ===================== //
static PT_THREAD (protothread_calculate (struct pt *pt))
{
    PT_BEGIN(pt);
    while(1) {
        PT_YIELD_TIME_msec(refreshRate);
        

        struct Ball *ti = head;
        struct Ball *tj = head;
        while(ti !=NULL){
            //Calculates the collisions between every ball
            while(tj != NULL) {
                signed short rij_x = ti->xpos - tj->xpos;
                signed short rij_y = ti->ypos - tj->ypos;
                signed short mag_rij = pow(rij_x,2) + pow(rij_y,2);
                //Checks if ti and tj are not pointing to the same ball,
                //If they close enough for a collision and there is no collision
                //delay.
                if(ti != tj && ti->delay + tj->delay == 0 && mag_rij < 4*pow(ballradius,2)) {
                    signed short vij_x = ti->xvel - tj->xvel;
                    signed short vij_y = ti->yvel - tj->yvel;
                    signed short temp = pow(2*pow(ballradius,2),2);
                    signed short deltaVi_x = -1*(rij_x * (rij_x * vij_x+ rij_y*vij_y))/temp;
                    signed short deltaVi_y = -1*(rij_y * (rij_x * vij_x+ rij_y*vij_y))/temp;
                    
                    //Updates the velocity
                    ti->xvel = ti->xvel + deltaVi_x;
                    ti->yvel = ti->yvel + deltaVi_y;
                    
                    tj->xvel = tj->xvel - deltaVi_x;
                    tj->yvel = tj->yvel - deltaVi_y;
                    
                    ti->delay = delay_master;
                    tj->delay = delay_master;
                    collisions++;
                }
                tj = tj->b;
            }
            //"Clears" the image of the last ball
            tft_fillCircle(ti->xpos,ti->ypos,ballradius,ILI9340_BLACK);
            
            //Updates the new position of the ball
            ti->xpos = ti->xpos + ti->xvel * refreshRate/10;
            ti->ypos = ti->ypos + ti->yvel * refreshRate/10;
            
            //checks for wall collisions
            if(ti->xpos > 240 || ti->xpos < 0) 
                ti->xvel = -1*ti->xvel;
            if(ti->ypos > 320 || ti->ypos < 0)
                ti->yvel = -1*ti->yvel;
            
            //Decrement the collide delay
            if(ti->delay > 0)
                ti->delay = ti->delay -1;
            ti = ti->b;
            tj = head;
        }
   }
    PT_END(pt);
}
// === Animation Thread =============================================
// move a disk
static PT_THREAD (protothread_anim(struct pt *pt))
{
    PT_BEGIN(pt);
    static int xc=10, yc=150, vxc=2, vyc=0;
      while(1) {
        // yield time 1 second
        PT_YIELD_TIME_msec(32);

        // erase disk
         tft_fillCircle(xc, yc, 4, ILI9340_BLACK); //x, y, radius, color
        // compute new position
         xc = xc + vxc;
         if (xc<5 || xc>235) vxc = -vxc;         
         //  draw disk
         tft_fillCircle(xc, yc, 4, ILI9340_GREEN); //x, y, radius, color
        // NEVER exit while
      } // END WHILE(1)
  PT_END(pt);
} // animation thread
Esempio n. 5
0
//======================= Refresh ========================= //
static PT_THREAD (protothread_refresh(struct pt *pt))
{
    PT_BEGIN(pt);
    while(1) {
        PT_YIELD_TIME_msec(10);
	    struct Ball *ti = head;
        while(ti != NULL){
            tft_fillCircle(ti->xpos, ti->ypos, ballradius, ILI9340_WHITE);
            ti = ti->b;
        }
   }
    PT_END(pt);
} // blink
Esempio n. 6
0
// === Animation Thread =============================================
static PT_THREAD (protothread_anim_balls(struct pt *pt))
{
    PT_BEGIN(pt); 
    while(1) {    
        PT_YIELD_TIME_msec(20);
        iterator = initial_ball;
        while(iterator != NULL) {       
            iterator2 = iterator->next;
            tft_fillCircle(fix2int16(iterator->xc), fix2int16(iterator->yc), RADIUS, ILI9340_BLACK);
            (iterator->xc) = (iterator->xc) + multfix16((iterator->vxc), drag);
            (iterator->yc) = (iterator->yc) + multfix16((iterator->vyc), drag);
            tft_fillCircle(fix2int16(iterator->xc), fix2int16(iterator->yc), RADIUS, ILI9340_WHITE);
            while(iterator2 != NULL)    {
                if (balls_collide(iterator, iterator2) && (iterator->hit_counter <= 0) && (iterator2->hit_counter <= 0))
                    computeVelocityChange(iterator, iterator2);
                else if (balls_collide(iterator, iterator2))
                {
                    iterator->hit_counter = COUNTER;
                    iterator2->hit_counter = COUNTER;
                }
                else{
                    iterator->hit_counter--;
					iterator2->hit_counter--;
                }
                iterator2 = iterator2->next;
            }
            // If the ball hits the paddle
            if ((myPaddle->xc+DIAMETER >= fix2int16(iterator->xc)) && (myPaddle->yc <= fix2int16(iterator->yc)) 
                    && ((myPaddle->yc+PADDLE_LEN) >= fix2int16(iterator->yc))){
                iterator->vxc = -(iterator->vxc);
                iterator->vyc = iterator->vyc + multfix16(int2fix16(myPaddle->vyc),pdrag);
                //DmaChnSetTxfer(dmaChn, sine_table2, (void*)&CVRCON, sizeof(sine_table2), 1, 1);
                //DmaChnEnable(dmaChn);
                //PT_YIELD_TIME_msec(2);
                //DmaChnDisable(dmaChn);  
            }
            // Else the ball went off the right edge
            else if (myPaddle->xc+DIAMETER >= fix2int16(iterator->xc))                                                    
            { 
                DmaChnSetTxfer(dmaChn, ball_scored, (void*)&CVRCON, sizeof(ball_scored), 1, 1);
                DmaChnEnable(dmaChn);
                PT_YIELD_TIME_msec(2);
                DmaChnDisable(dmaChn);  
                deleteBall(iterator); 
                score--;
            }
            // Calculate top bin
            else if ((iterator->xc) <= int2fix16(250+2) && iterator->xc >= int2fix16(175-2) && iterator->yc <= int2fix16(25+9))    
                { deleteBall(iterator); score++;}   
            // Calculate bottom bin
            else if ((iterator->xc) <= int2fix16(250+2) && iterator->xc >= int2fix16(175-2) && iterator->yc >= int2fix16(233-2))   
                { deleteBall(iterator); score++;}
            // Bounce off right wall
            else if ((iterator->xc) >= int2fix16(315))                                      
                (iterator->vxc) = -(iterator->vxc); 
            // Bounce off top or bottom wall
            else if ((iterator->yc) <= int2fix16(25) ||(iterator->yc) >= int2fix16(233))    
                (iterator->vyc) = -(iterator->vyc);         
            iterator = iterator->next;   
        }
    } // END WHILE(1)
    PT_END(pt);
} // animation thread
Esempio n. 7
0
void menu(void) {
    uint16_t x,y,z;
    while (1) {
        switch (selection((const char**)menu_table,10)) {
        case 0:
#ifdef MT9D111
            setRes(QVGA);
            setColor(RGB565);
            MT9D111Refresh();
            editRegs(0);
#else
            setColor(RGB565);
            setRes(QVGA);
            editRegs();
#endif
            break;
        case 1:
#ifdef MT9D111
            setRes(QVGA);
            setColor(RGB565);
            MT9D111Refresh();
            editRegs(1);
#else
#ifdef ov7740
            setmatrix(selection((const char**)maxtrix_table,2));
#else
            setmatrix(selection((const char**)maxtrix_table,3));
#endif
            tft_setOrientation(1);
            capImg();
            tft_setDisplayDirect(DOWN2UP);
#endif
            break;
        case 2:
#ifdef ov7670
            initCam(0);
#else
            initCam();
#endif
            break;
#ifndef MT9D111
        case 3:
            //compare matrices
            tft_setOrientation(1);
            do {
                getPoint(&x,&y,&z);
                uint8_t a;
#ifdef ov7670
                for (a=0; a<3; a++) {
#elif defined ov7740
                for (a=0; a<2; a++) {
#endif
                    setmatrix(a);
                    capImg();
                }
            }
            while (z < 10);
            tft_setDisplayDirect(DOWN2UP);
            break;
#endif
        case 4:
            setColor(RGB565);
            setRes(QQVGA);
#ifdef MT9D111
            MT9D111Refresh();
#endif
            do {
                getPoint(&x,&y,&z);
                tft_setOrientation(1);
                capImgqqvga(160);
                tft_setDisplayDirect(DOWN2UP);
            } while(z<10);
            setRes(QVGA);
            break;
        case 5:
#ifdef ov7670
            setColor(RGB565);
#endif
            gammaEdit();
            break;
        case 6:
            //File browser
            //start by listing files
#ifdef haveSDcard
            browserSD();
#else
            tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE);
            _delay_ms(666);
#endif
            break;
        case 7:
#ifdef ov7670
        {   uint8_t pick=selection((const char**)wb_table,7);//registers from http://thinksmallthings.wordpress.com/2012/10/25/white-balance-control-with-ov7670/
            if(pick==1||pick==2) {
                wrReg(0x13, 0xE7);
                wrReg(0x6F, 0x9E|(pick&1));
            } else {
                wrReg(0x13, 0xE5);
                switch(pick) {
                case 2:
                    wrReg(0x01, 0x5A);
                    wrReg(0x02, 0x5C);
                    break;
                case 3:
                    wrReg(0x01, 0x58);
                    wrReg(0x02, 0x60);
                    break;
                case 4:
                    wrReg(0x01, 0x84);
                    wrReg(0x02, 0x4C);
                    break;
                case 5:
                    wrReg(0x01, 0x96);
                    wrReg(0x02, 0x40);
                    break;
                }
            }
            tft_setOrientation(1);
            setRes(QVGA);
            setColor(RGB565);
            capImg();
            tft_setDisplayDirect(DOWN2UP);
        }
#endif
        break;
        case 8:
#ifdef ov7670
            wrReg(0x1e,rdReg(0x1e)&(~(1<<5))&(~(1<<4)));
#endif
            {
#ifdef MT9D111
                uint8_t reso=selection((const char**)res_tab,4);
#else
                uint8_t reso=selection((const char**)res_tab,3);
#endif
#ifdef MT9D111
                wrReg16(0xF0,2);//page 2
                wrReg16(0x0D,0);
                setColor(YUV422);
#endif
                switch(reso) {
                case 0:
#ifdef ov7670
                    wrReg(REG_COM7, COM7_BAYER); // BGBGBG... GRGRGR...
#elif defined MT9D111
                    //setup jpeg
                    MT9D111JPegCapture();
#endif
                    break;
                case 1:
#ifdef MT9D111
                    setRes(SVGA);
#else
                    setRes(QVGA);
                    setColor(YUV422);
#endif
                    break;
#ifdef MT9D111
                case 2:
                    setRes(QVGA);
                    break;
#endif
                default:
                    goto theEnd;
                    break;
                }
#ifdef ov7670
                _delay_ms(200);
                if(reso)
                    wrReg(0x11,1);
                else
                    wrReg(0x11,2);
#endif
                tft_setOrientation(1);
                do {
#ifdef MT9D111
                    switch(reso) {
                    case 0:
                    {   uint32_t jpgSize=capJpeg();
                        serialWrB('R');
                        serialWrB('D');
                        serialWrB('Y');
                        uint16_t w;
                        uint8_t h=0;
                        serialWrB(jpgSize&255);
                        serialWrB(jpgSize>>8);
                        serialWrB(jpgSize>>16);
                        serialWrB(jpgSize>>24);
                        while(jpgSize) {
                            if(jpgSize>=640) {
                                for (w=0; w<320; ++w) {
                                    tft_setXY(h,w);
                                    BSend();
                                }
                                ++h;
                                jpgSize-=640;
                            } else {
                                for(w=0; w<jpgSize/2; ++w) {
                                    tft_setXY(h,w);
                                    BSend();
                                }
                                if(jpgSize&1) {
                                    tft_setXY(h,w);
                                    uint16_t res=tft_readRegister(0x22);
                                    serialWrB(res>>8);
                                }
                                jpgSize=0;
                            }
                        }
                    }
                    break;
                    case 1:
                        capImgPC();
                        break;
                    case 2:
                        capImgPCqvga();
                        break;
                    }
#else
                    if(reso)
                        capImgPCqvga();
                    else
                        capImgPC();
#endif
                    getPoint(&x,&y,&z);
                } while(z<10);
theEnd:
                tft_setDisplayDirect(DOWN2UP);
            }
            break;
        case 9:
            switch(selection((const char**)menu_tablep2,3)) {
            case 0:
            {
                tft_drawImage_P(exit_icon,32,32,0,0);
                uint16_t x1,y1;
                do {
                    getPoint(&x,&y,&z);
                } while(z<10);
                if((y<=32)&&(x<=32))
                    break;
                tft_fillCircle(x,y,4,WHITE);
                while(1) {
                    x1=x;
                    y1=y;
                    do {
                        getPoint(&x,&y,&z);
                    } while(z<10);
                    tft_fillRectangle(224,320,16,36,BLACK);
                    tft_fillCircle(x1,y1,4,BLACK);
                    tft_fillCircle(x,y,4,WHITE);
                    if((y<=32)&&(x<=32))
                        break;
                    char temp[6];
                    utoa(x,temp,10);
                    tft_drawString(temp,224,320,1,WHITE);
                    utoa(y,temp,10);
                    tft_drawString(temp,232,320,1,WHITE);
                }
            }
            break;
            case 1:
                //time lapse
#ifdef MT9D111
                //MT9D111Refresh();
                //Since This is a time lapse we want to be in "video" mode
                MT9D111JPegCapture();
                /*do{
                	_delay_ms(10);
                	wrReg16(0xC6,(1<<15)|(1<<13)|(1<<8)|4);
                }while(rdReg16(0xC8)<4);
                waitStateMT9D111(3);*/
#endif
#ifdef haveSDcard
                {
                    char buf[24];
                    uint16_t imgc=0;
                    tft_setOrientation(1);
                    do {
                        FIL Fo;
#ifdef MT9D111
                        uint32_t jpgSize=capJpeg();
#else
                        capImg();
#endif
                        utoa(imgc,buf,10);
#ifdef MT9D111
                        strcat(buf,".JPG");
#else
                        strcat(buf,".RAW");
#endif
                        f_open(&Fo,buf,FA_WRITE|FA_CREATE_ALWAYS);
                        ++imgc;
                        UINT written;
                        uint16_t w;
                        uint8_t h;
                        uint16_t cpybuf[320];
#ifdef MT9D111
                        h=0;
                        uint8_t * cpyptr=cpybuf;
                        for(w=0; w<619; ++w)
                            *cpyptr++=pgm_read_byte_near(jpegHeader+w);
                        f_write(&Fo,cpybuf,619,&written);
                        while(jpgSize) {
                            if(jpgSize>=640) {
                                for (w=0; w<320; ++w) {
                                    tft_setXY(h,w);
                                    cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22));//Either bytes need to be swapped or a byte is being missed
                                }
                                f_write(&Fo,cpybuf,640,&written);
                                ++h;
                                jpgSize-=640;
                            } else {
                                for(w=0; w<jpgSize/2; ++w) {
                                    tft_setXY(h,w);
                                    cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22));
                                }
                                f_write(&Fo,cpybuf,jpgSize,&written);
                                if(jpgSize&1) {
                                    tft_setXY(h,w);
                                    cpybuf[w]=tft_readRegister(0x22);
                                    f_write(&Fo,&cpybuf[w],1,&written);
                                }
                                jpgSize=0;
                            }
                        }
                        cpybuf[0]=0xFFD9;
                        f_write(&Fo,cpybuf,2,&written);
#else
                        for (h=0; h<240; ++h) {
                            for (w=0; w<320; ++w) {
                                tft_setXY(h,w);
                                cpybuf[w]=tft_readRegister(0x22);
                            }
                            f_write(&Fo,cpybuf,640,&written);
                        }
#endif
                        f_close(&Fo);
                        getPoint(&x,&y,&z);
                    } while(z<10);
                    tft_setDisplayDirect(DOWN2UP);
#ifdef MT9D111
                    MT9D111DoPreview();
#endif
                }
#else
                tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE);
                _delay_ms(666);
#endif
                break;
            case 2:
                //previous page
                break;
            }
            break;
        }
    }
}
Esempio n. 8
0
//======================= Refresh ========================= //
//Does Ball calculations and Draws the necessary elements on the screen 
static PT_THREAD (protothread_refresh(struct pt *pt))
{
    PT_BEGIN(pt);
    PT_YIELD_TIME_msec(100);
    //waits for the scoreboard to be set up
    while(1) {
        
        while (timeElapsed <=60) {
            
            PT_YIELD_TIME_msec(10);
            DmaChnDisable(dmaChn);
            DmaChnDisable(dmaChn2);
            //Generates a new ball at a given interval
            if(ballgen >= 10) {
                int troll1 = -((rand()) % 2)-1;
                int troll2 = ((rand()) % 6) - 3;
                struct Ball *temp = Ball_create(320,120,troll1,troll2,(numBalls+1)*500,0,NULL);
                temp->b = head;
                head = temp;
                ballgen = 0;
                numBalls++;
            }
            else
                ballgen ++;

            //collision calculations
            struct Ball *ti = head;
            struct Ball *tj = NULL;
            if(ti != NULL)
                tj = ti->b;
            while(ti !=NULL){
                //Calculates the collisions between every ball
                while(tj != NULL) {
                    int rij_x = ti->xpos - tj->xpos;
                    int rij_y = ti->ypos - tj->ypos;
                    int mag_rij = pow(rij_x,2) + pow(rij_y,2);
                    //Checks if ti and tj are not pointing to the same ball,
                    //If they close enough for a collision and there is no collision
                    //delay.
                    if( ti->delay + tj->delay == 0 && mag_rij < dist) {
                        int vij_x = ti->xvel - tj->xvel;
                        int vij_y = ti->yvel - tj->yvel;
                        if (mag_rij==0) {
                            mag_rij=dist;
                        }
                        int deltaVi_x = (int)((-1*(rij_x) * ((((rij_x * vij_x)+ (rij_y*vij_y)) << 7)/mag_rij)) >> 7);
                        int deltaVi_y = (int)((-1*(rij_y) * ((((rij_x * vij_x)+ (rij_y*vij_y)) << 7)/mag_rij)) >> 7);
                        /*
                        tft_fillRoundRect(0,30, 320, 14, 1, ILI9340_BLACK);// x,y,w,h,radius,color
                        tft_setCursor(0, 30);
                        tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2);
                        sprintf(buffer,"%d:%d", (-1*(rij_x)/128 * (128*((rij_x * vij_x)+ (rij_y*vij_y))/mag_rij)), mag_rij);
                        tft_writeString(buffer);
                        */
                        //Updates the velocity
                        ti->xvel = ti->xvel + deltaVi_x;
                        ti->yvel = ti->yvel + deltaVi_y;

                        tj->xvel = tj->xvel - deltaVi_x;
                        tj->yvel = tj->yvel - deltaVi_y;

                        ti->delay = delay_master;
                        tj->delay = delay_master;
                    }
                    tj = tj->b;
                }

                //checks for wall collisions

                if(ti->xpos >= 320*scale || ti->xpos <= 0) 
                    ti->xvel = -1*ti->xvel;
                if(ti->ypos >= 240*scale || ti->ypos <= 35*scale) {
                    ti->yvel = -1*ti->yvel;
                    if (ti->xpos > 120*scale && ti->xpos < 200*scale) { //check for catch bin
                        ti->delay=-1; //set to -1 to indicate +1 point
                    }
                }
                //calculates the drag

                if(ti->xvel > 0)
                    ti->xvel = ti->xvel - ti->xvel/drag;
                else
                    ti->xvel = ti->xvel + ti->xvel/drag;
                if(ti->yvel > 0)
                    ti->yvel = ti->yvel - ti->yvel/drag;
                else
                    ti->yvel = ti->yvel - ti->yvel/drag;

                // Check for paddle Collisions
                if(abs(paddle_xpos-ti->xpos/scale) <= ballradius && ti->delay == 0)
                    if(ti->ypos/scale > paddle_ypos - half_paddle_length && ti->ypos/scale < paddle_ypos + half_paddle_length) {
                        ti->xvel = -1*ti->xvel;
                        ti->yvel = ti->yvel + paddle_drag*paddle_v;
                        ti->delay=delay_master;
                    }
                //Decrement the collide delay
                if(ti->delay > 0)
                    ti->delay = ti->delay -1;


                //iterates through the next set
                ti = ti->b;
                if(ti != NULL)
                    tj = ti->b;

                //removes the last element if the limit is reached
                if(numBalls > maxBalls && tj->b == NULL) { 
                    tft_fillCircle(tj->xpos/scale,tj->ypos/scale,ballradius,ILI9340_BLACK); //erases from the screen
                    ti->b = NULL;
                    numBalls--;
                    score++;
                    //free(tj);
                }

            }
            // Calculates position of the paddle and draw
            //TODO: Calculate paddle position
            tft_drawLine(paddle_xpos,paddle_ypos - half_paddle_length, paddle_xpos, paddle_ypos + half_paddle_length, ILI9340_BLACK);
            paddle_v=paddle_ypos;
            paddle_ypos=(adc_9*240)/1023;
            paddle_v=paddle_ypos-paddle_v;
            tft_drawLine(paddle_xpos,paddle_ypos - half_paddle_length, paddle_xpos, paddle_ypos + half_paddle_length, ILI9340_WHITE);

            // Now it calculates the new position
            ti = head;
            tj = head;
            while(ti != NULL){
                //"Clears" the image of the last ball
                tft_fillCircle(ti->xpos/scale,ti->ypos/scale,ballradius,ILI9340_BLACK);

                //Updates the new position of the ball
                ti->xpos = ti->xpos + ti->xvel;
                ti->ypos = ti->ypos + ti->yvel;

                //ensures the positions are within bounds
                //If the pos is less than 0 then we remove it
                //delay must also not be -1 (ie >=0)
                if(ti->xpos > paddle_xpos && ti->delay != -1) {
                    if(ti->xpos > 320*scale)
                        ti->xpos = 320*scale;

                    if(ti->ypos > 240*scale)
                        ti->ypos = 240*scale;
                    else if(ti->ypos < 35*scale)
                        ti->ypos = 35*scale;

                    if(ti->delay > 0)
                         tft_fillCircle(ti->xpos/scale, ti->ypos/scale, ballradius, ILI9340_WHITE);
                    else
                        tft_fillCircle(ti->xpos/scale, ti->ypos/scale, ballradius, ti->color);
                }
                else { //REMOVES THE BALL IF IT CROSSES THE BOUNDARY
                    if (ti->delay==-1) { //check if went into catch bins
                        score++;
                        DmaChnEnable(dmaChn2);
                    }
                    else {
                        	DmaChnEnable(dmaChn);
                            
                        score--;
                    }
                    if(ti == head)
                        head = head->b;
                    else
                        tj->b = ti->b;
                    numBalls--;
                    //free(ti);
                }
                tj = ti;//what does this do?
                ti = ti->b;
            }
            frames ++;
       }
       
       tft_fillRoundRect(0,35, 320, 205, 1, ILI9340_BLACK);// x,y,w,h,radius,color
       DmaChnDisable(dmaChn);
       DmaChnDisable(dmaChn2);
       DmaChnEnable(dmaChn3);
       while (1) {
           
            tft_setCursor(20, 120);
            tft_setTextColor(ILI9340_WHITE); tft_setTextSize(4);
            sprintf(buffer,"Game Over!");
            tft_writeString(buffer);
       }
   }