Continuous Part Review for Road Test of Infineon Smart Power Switch Bundle
4 Test on Switch Shields
4.1 Test on Low-Side Switch Shield with BTF3050TE for Arduino
Detail information on this Shield can be found https://www.infineon.com/cms/cn/product/evaluation-boards/shield_btf3050te/ . Demo code on Arduino or Dave.
Here is the codes
// Pin definition #define LED_0 4 #define LED_1 A4 #define LED_2 2 #define LED_3 10 #define ONOFF_1 A1 #define ONOFF_2 A2 #define ONOFF_3 A3 #define PWM_1 6 #define PWM_2 11 #define PWM_3 9 #define S_0 8 #define S_1 5 #define S_2 3 #define S_3 7 #define S_4 A0 #define SRP_1 13 #define SRP_2 12 #define SRP_3 A5 /* Initialization of global variables Change these parameters to modify frequency and initial duty cycle*/ int input; int duty_cycle[3] = { 204, 204, 204}; // Variables, containing the desired initial duty cycle value of each PWM in (1/2.55)% int freq_divisor[3] = { 1, 1, 1 }; // Frequeny of PWMs in 62500Hz/freq[0], 31250Hz/freq[1], 31250Hz/freq[2] // Available values for freq_divisor[0] and freq_divisor[2] are 1,8,64,256,1024 // Available values for freq_divisor[1] are 1,8,32,64,128,256,1024 int res = 10; // Debounce cycles bool debounce(int pin) { // debounces digitally the tactile push button if(digitalRead(pin)) { // INPUT: pin to debounce for(int32_t i; i<160000;i++) {} if(digitalRead(pin)) { while(digitalRead(pin)) {} return true; } } return false; } void increaseDutyCycle(int number) { // increases the duty cycle by on discrete step equal to 2.55% duty_cycle[number]+=res; // INPUT: Number of PWM if(duty_cycle[number] > 255) duty_cycle[number] = 255; } void decreaseDutyCycle(int number) { // decreases the duty cycle by on discrete step equal to 2.55% duty_cycle[number]-=res; // INPUT: Number of PWM if(duty_cycle[number] < 0) duty_cycle[number] = 0; } void setPwmFrequency (int pin, int divisor) { // sets PWM frequency byte divisor_byte; // INPUT: Number of PWM, divisor // refer to l.25-28 or arduino homepage for further information about the divisor if(pin == 5 || pin == 6 || pin == 9 || pin == 10){ switch(divisor){ case 1: divisor_byte = 0x01; break; case 8: divisor_byte = 0x02; break; case 64: divisor_byte = 0x03; break; case 256: divisor_byte = 0x04; break; case 1024: divisor_byte = 0x05; break; default: return; } if(pin == 5 || pin == 6){ TCCR0B = TCCR0B & 0b11111000 | divisor_byte; } else { TCCR1B = TCCR1B & 0b11111000 | divisor_byte; } } else if(pin == 3 || pin == 11){ switch(divisor){ case 1: divisor_byte = 0x01; break; case 8: divisor_byte = 0x02; break; case 32: divisor_byte = 0x03; break; case 64: divisor_byte = 0x04; break; case 128: divisor_byte = 0x05; break; case 256: divisor_byte = 0x06; break; case 1024: divisor_byte = 0x7; break; default: return; } TCCR2B = TCCR2B & 0b11111000 | divisor_byte; } } void setup() { // Pin assignment and setting PWM frequency pinMode(LED_0, OUTPUT); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); pinMode(LED_3, OUTPUT); pinMode(ONOFF_1, INPUT); pinMode(ONOFF_2, INPUT); pinMode(ONOFF_3, INPUT); pinMode(S_0, INPUT); pinMode(S_1, INPUT); pinMode(S_2, INPUT); pinMode(S_3, INPUT); pinMode(S_4, INPUT); pinMode(SRP_1, INPUT); pinMode(SRP_2, INPUT); pinMode(SRP_3, INPUT); setPwmFrequency(PWM_1, freq_divisor[0] ); setPwmFrequency(PWM_2, freq_divisor[1] ); setPwmFrequency(PWM_3, freq_divisor[2] ); } void loop() { if(debounce(S_0)) // Toggles LED0; LED0 indicates whether the duty cycle of one of the PWMs will increase or decrease, when pressing S1, S2 or S3 digitalWrite( LED_0, !digitalRead(LED_0)); digitalWrite(LED_1, digitalRead(SRP_1)); // LED1, LED2 and LED3 will emit light once a fault feedback is present on one corresponsing Low Side Switch digitalWrite(LED_2, digitalRead(SRP_2)); digitalWrite(LED_3, digitalRead(SRP_3)); if(debounce(S_1)){ // S1, S2 and S3 will change the duty cycle of the corresponding Low Side Switch if(digitalRead(LED_0)) { increaseDutyCycle(0); } else { decreaseDutyCycle(0); } } if(debounce(S_2)) if(digitalRead(LED_0)) { increaseDutyCycle(1); } else { decreaseDutyCycle(1); } if(debounce(S_3)) if(digitalRead(LED_0)) { increaseDutyCycle(2); } else { decreaseDutyCycle(2); } if(debounce(S_4)) { // S4 resets the Fault Feedback; SRP1, SRP2 and SRP3 will be pulled to ground and thus reset the Faul Feedback, afterwards the pins will be set to input again. pinMode(SRP_1, OUTPUT); // For further information regarded the Fault Feedback, please refer to the datasheet of the BTF3050TE pinMode(SRP_2, OUTPUT); pinMode(SRP_3, OUTPUT); digitalWrite(SRP_1, LOW); digitalWrite(SRP_2, LOW); digitalWrite(SRP_3, LOW); for(int32_t i; i<160000;i++) {} pinMode(SRP_1, INPUT); pinMode(SRP_2, INPUT); pinMode(SRP_3, INPUT); } if(digitalRead(ONOFF_1)) { // The corresponding Low Side Switch will turn on/off depening on the DIP-Switch channels. analogWrite(PWM_1, duty_cycle[0]); } else { analogWrite(PWM_1, 0); } if(digitalRead(ONOFF_2)) { analogWrite(PWM_2, duty_cycle[1]); } else { analogWrite(PWM_2, 0); } if(digitalRead(ONOFF_3)) { analogWrite(PWM_3, duty_cycle[2]); } else { analogWrite(PWM_3, 0); } }
According to the code, button s_0 toggles LED0 for PWM increase or decrease. s_1, s_2, s_3 triggers the increase or decrease action.
as to,
int freq_divisor[3] = { 1, 1, 1 }; // Frequeny of PWMs in 62500Hz/freq[0], 31250Hz/freq[1], 31250Hz/freq[2]
frequency divisor shall be properly set, since Capable of PWM is up to 14KHz (at 10% duty cycle), 62.5kHz shall put the part overheated and can not work properly. DIPselection swith shall be set as on/off status to enable output of the power. Following the steps,
- Choose up to three appropriate loads,
- Connect the Low Side Switch Shield for example to the Arduino Uno R3 and , connect the board with the proper USB cable
- Program the controller board with the Low Side Switch software above, set the freq_divisor with right value,
- Then Connect the GND of shield’s screw terminal with the ground of the power supply and connect the three outputs of the screw terminal with your loads and the loads to the power supply of 5V
- Then the LED can be controlled with this s1, s2,s3 buttong, reset PWM value with s4.
Here is the photo taken during this test.The LED is on, when the DIP switch is put to position ON, change the PWM by botton S3 for LED3.
The LED is OFF when the DIP is in OFF position.
Enlarge picture of DIP switch.
4.2 Test on SHIELD_BTS50010-1TAD
Similar product SHIELD_BTS50015-1TAD with comes with BTS50015-1TAD (RDS(ON) 1.5mΩ), an ultra-low ohmic smart high-side power switch from the Power PROFET family. While for this board comes with BTS50010-1TAD (RDS(ON) 1.0mΩ), the lowest ohmic smart high-side power switch available in the market. In this part I would use stand-alone mode in test the SHIELD as follows,
First, Choose an appropriate load, for example a valve or glow plug. Then connect the High Side Switch Shield to the load and an external switch corresponding to the example circuit. Turn on Power, power supply should not exceed 18V for nominal operation and the load will run..
Stand alone mode makes use of simple configuration and more flexible application. Of course, Test-program for XMC1100 Bootkit together with BTS50015-1TAD shield for Arduino can provide more control. ADC will continuously restart to measure at three analog input´s, Measurement values will be provided in the ADC-interrupt routine "ADC_Measurement_Handler.c". Push button S2 will occur an interrupt if pushed and switches Output_Switch and LED2.
The stand alone mode is easy to use with the following connections.
The LED is ON when P0.3 is 5V,
The LED is OFF when P0.3 is GND.
4.3 Test on 24V Protected Switch Shield with BTT6030-2EKA and BTT6020-1EKA for Arduino
The 24V Protected Switch Shield can be controlled with the general logic IO-Ports of a microcontroller. On board of the 24V Protected Switch Shield are two BTT6030-2EKA and one BTT6020-1EKA PROFETTM +24V. Each of the BTT6030-2EKA features two 32 mΩ Smart high-side power switch-channels, whereas the BTT6020- 1EKA features a single 20 mΩ channel. In total the shield provides five Smart High-Side Power Switch Channels. Each is built by a vertical N-channel power MOSFET with charge pump. Due to the integrated charge pump the channels can be controlled by standard digital IOs (3.3 V and 5 V supported). The 24V Protected Switch Shield can be easily connected to any Arduino compatible board like the XMC1100 Boot Kit via headers.
To understand the wiring, principle diagram is as follows. Difference between BTT6030-2EKA and BTT6020 can be easily found out from this diagram.
The DAVE development IDE can be downloaded and unzipped for use CLEAN INSTALLATION. Here is the code in main.c for your reference. The project shall be imported.
/* main.c */ /* Description: * * Demo software for the Protected Switch Shield for Arduino with PROFET+ 24V V1.0. * The Software drives all 5 channels in different PWM configurations: * * channel0 of PROFET0: 100% on * channel1 of PROFET0: 50% duty cycle @200Hz * * channel0 of PROFET1: 75% duty cycle @320Hz * channel1 of PROFET1: 60% duty cycle @400Hz * * channel0 of PROFET2: 80% duty cycle @120Hz * * The duty cycles at the various frequencies can be changed via the corresponding PWM APPs or during runtime using the API. * Please refer to the APP Help for more information how to do this. (right click on the APP->APP Help) * * As each sense signal (IS PIN of PROFET) is connected to an own ADC channel, they do not interfere with each other. So the DEN (Diagnostic ENable) of the three PROFETs is always enabled. * The ADC measures continuously the sense signal, but calculates the load current only if the corresponding channel is turned on. * * The provided code shall only demonstrate how to drive PROFET channels with PWM using a XMC µC and how to measure the sense current and retrieve the load current out of it. * It should give the user a hint how to work with the Protected Switch Shield. * * */ #include <XMC1100.h> #include <DAVE.h> //Declarations from DAVE Code Generation (includes SFR declaration) #define FALSE 0 #define TRUE 1 #define RIS 1200 //IS Resistor in Ohm #define ADCFACT 819 //Factor to get Voltage from ADC result with 12Bit conversion (4095/5V) typedef struct ProfetChannel{ bool on; //flag to indicate if the channel is currently switched on uint32_t current; //the load current of the channel }ProfetChannel; typedef struct ProfetStatus{ ProfetChannel channel0; ProfetChannel channel1; uint16_t kilis; //the kilis of the Device (ratio between load current and sense current) you get it from the Spec }ProfetStatus; ProfetStatus Profet0; ProfetStatus Profet1; ProfetStatus Profet2; /** * @brief main() - Application entry point * * <b>Details of function</b><br> * This routine is the application entry point. It is invoked by the device startup code. It is responsible for * invoking the App initialization dispatcher routine - DAVE_Init() and hosting the place-holder for user application * code. */ int main(void) { DAVE_STATUS_t status; status = DAVE_Init(); /* Initialization of DAVE Apps */ if(status == DAVE_STATUS_FAILURE) { /* Placeholder for error handler code. The while loop below can be replaced with an user error handler */ XMC_DEBUG(("DAVE Apps initialization failed with status %d\n", status)); while(1U) { } } //init of PROFETs on, current Profet0.channel0 = (ProfetChannel){FALSE, 0}; Profet0.channel1 = (ProfetChannel){FALSE, 0}; Profet0.kilis = 2240; Profet1.channel0 = (ProfetChannel){FALSE, 0}; Profet1.channel1 = (ProfetChannel){FALSE, 0}; Profet1.kilis = 2240; Profet2.channel0 = (ProfetChannel){FALSE, 0}; //PROFET 2 is a one channel device (BTT6020-1EKB) Profet2.kilis = 2950; /* Placeholder for user application code. The while loop below can be replaced with user application code. */ DIGITAL_IO_SetOutputHigh(&IN0_P0); //channel 0 of PROFET 0 is switched on statically, means there is no PWM driving this channel. Profet0.channel0.on = TRUE; ADC_MEASUREMENT_StartConversion(&SENSE_MEASUREMENT); //since the ADC is configured to convert continuously, it's sufficient to start the conversion once. while(1U) { } } /** * @brief isr_profet0() - Interrupt Service Routine PROFET0 * * handles the period and compare events of the PWM for the PROFET0 * * -PERIOD: turn off channel 1 * -COMPARE: turn on channel 1 */ void isr_profet0(void){ if(PWM_GetInterruptStatus(&PWM_PROFET0_C1, PWM_INTERRUPT_PERIODMATCH)){ PWM_ClearEvent(&PWM_PROFET0_C1, PWM_INTERRUPT_PERIODMATCH); //PERIOD: Profet0.channel1.on = FALSE; } if(PWM_GetInterruptStatus(&PWM_PROFET0_C1, PWM_INTERRUPT_COMPAREMATCH)){ PWM_ClearEvent(&PWM_PROFET0_C1, PWM_INTERRUPT_COMPAREMATCH); //Compare: Profet0.channel1.on = TRUE; } } /** * @brief isr_profet1() - Interrupt Service Routine PROFET 1 * * handles the period and compare events of the PWMs for the PROFET 1 * * -PERIOD_c0: turn off channel 0 * -COMPARE_c0: turn on channel 0 * -PERIOD_c1: turn off channel 1 * -COMPARE_c1: turn on channel 1 */ void isr_profet1(void){ if(PWM_GetInterruptStatus(&PWM_PROFET1_C0, PWM_INTERRUPT_COMPAREMATCH)){ PWM_ClearEvent(&PWM_PROFET1_C0, PWM_INTERRUPT_COMPAREMATCH); //Comparec0: Profet1.channel0.on = TRUE; } if(PWM_GetInterruptStatus(&PWM_PROFET1_C0, PWM_INTERRUPT_PERIODMATCH)){ PWM_ClearEvent(&PWM_PROFET1_C0, PWM_INTERRUPT_PERIODMATCH); //PERIODc0: Profet1.channel0.on = FALSE; } if(PWM_GetInterruptStatus(&PWM_PROFET1_C1, PWM_INTERRUPT_COMPAREMATCH)){ PWM_ClearEvent(&PWM_PROFET1_C1, PWM_INTERRUPT_COMPAREMATCH); //Comparec1: DIGITAL_IO_SetOutputHigh(&IN1_P1); Profet1.channel1.on = TRUE; } if(PWM_GetInterruptStatus(&PWM_PROFET1_C1, PWM_INTERRUPT_PERIODMATCH)){ PWM_ClearEvent(&PWM_PROFET1_C1, PWM_INTERRUPT_PERIODMATCH); //PERIODc1: DIGITAL_IO_SetOutputLow(&IN1_P1); Profet1.channel1.on = FALSE; } } /** * @brief isr_profet2() - Interrupt Service Routine PROFET 2 * * handles the period and compare events of the PWM for the PROFET 2 * * -PERIOD: turn off * -COMPARE: turn on */ void isr_profet2(void){ if(PWM_GetInterruptStatus(&PWM_PROFET2, PWM_INTERRUPT_PERIODMATCH)){ PWM_ClearEvent(&PWM_PROFET2, PWM_INTERRUPT_PERIODMATCH); //PERIOD: DIGITAL_IO_SetOutputLow(&IN_P2); Profet2.channel0.on = FALSE; } if(PWM_GetInterruptStatus(&PWM_PROFET2, PWM_INTERRUPT_COMPAREMATCH)){ PWM_ClearEvent(&PWM_PROFET2, PWM_INTERRUPT_COMPAREMATCH); //Compare: DIGITAL_IO_SetOutputHigh(&IN_P2); Profet2.channel0.on = TRUE; } } /** * @brief isr_adcFinished() - Interrupt Service Routine for the ADC * * This interrupt is triggered when the ADC finished conversion of one channel. * Since the XMC1100 has only one global Register for all ADC measurements. It's necessary to check which channel was converted. * The ADC is configured to continuously convert the channels, but the result register is only overwritten after a read. * Here is the mapping between the measurement channel and the PROFET: * channel 0 - IS of PROFET0 * channel 1 - IS of PROFET1 * channel 2 - IS of PROFET2 * * When a channel is converted and its corresponding PROFET channel is switched on, the load current is calculated out of the ADC result and stored in the corresponding global ProfetStatus variable. * This value could then be used to implement a protection strategy. e.g. turn the channel off after an over current shutdown happened x times in a row. * */ void isr_adcFinished(void){ static bool dselen = FALSE; static uint8_t i = 0; uint8_t channel; uint32_t convres, vis, iis; uint32_t result = ADC_MEASUREMENT_GetDetailedResult(&SENSE_MEASUREMENT); channel = (result & VADC_GLOBRES_CHNR_Msk) >> VADC_GLOBRES_CHNR_Pos; convres = (result & VADC_GLOBRES_RESULT_Msk) >>((uint32_t)SENSE_MEASUREMENT.iclass_config_handle->conversion_mode_standard * (uint32_t)2); switch(channel){ case 0: //PROFET0 if(dselen && Profet0.channel1.on){ convres = convres*100000; //increase number to avoid losing important digits during division vis = convres/ADCFACT; //Voltage from ADCresult iis = vis/RIS; //IS current = Vis / RIS; I = U/R) Profet0.channel1.current = (iis*Profet0.kilis)/100; //Iis * kilis = Iout divide by 100 to get it in mA }else if(Profet0.channel0.on){ convres = convres*100000; //increase number to avoid losing important digits during division vis = convres/ADCFACT; //Voltage from ADCresult iis = vis/RIS; //IS current = Vis / RIS; I = U/R) Profet0.channel0.current = (iis*Profet0.kilis)/100; //Iis * kilis = Iout divide by 100 to get it in mA } break; case 1: //PROFET1 if(dselen && Profet1.channel1.on){ convres = convres*100000; //increase number to avoid losing important digits during division vis = convres/ADCFACT; //Voltage from ADCresult iis = vis/RIS; //IS current = Vis / RIS; I = U/R) Profet1.channel1.current = (iis*Profet1.kilis)/100; //Iis * kilis = Iout divide by 100 to get it in mA }else if(Profet1.channel0.on){ convres = convres*100000; //increase number to avoid losing important digits during division vis = convres/ADCFACT; iis = vis/RIS; //IS current = Vis / RIS; I = U/R) Profet1.channel0.current = (iis*Profet1.kilis)/100; //Iis * kilis = Iout divide by 100 to get it in mA } break; case 2: //PROFET2 if(Profet2.channel0.on){ convres = convres*100000; //increase number to avoid losing important digits during division vis = convres/ADCFACT; //Voltage from ADCresult iis = vis/RIS; //IS current = Vis / RIS; I = U/R) Profet2.channel0.current = (iis*Profet2.kilis)/100; //Iis * kilis = Iout divide by 100 to get it in mA } } if(i++ >= 2){ // 3 Results measured (PROFET0..2) toggle the DSEL Pins to measure now the other channels. // DSEL high: channel 1 of PROFET0&1, DSEL low channel 0 of PROFET0&1. PROFET2 has only one channel and therefore no DSEL PIN. dselen = !dselen; i = 0; if(dselen){ DIGITAL_IO_SetOutputHigh(&DSEL_P0); DIGITAL_IO_SetOutputHigh(&DSEL_P1); }else{ DIGITAL_IO_SetOutputLow(&DSEL_P0); DIGITAL_IO_SetOutputLow(&DSEL_P1); } } }
Then build the project and downloads into XMC-1100 for the running of the HV protection shield.
The function is similar. While more work shall be done to make the best protection and high efficiency to be realized Then.
Refer to the following blog for detail information.